热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

螺旋矩阵c++语言_一起刷leetcode之螺旋矩阵(头条和美团真题)

微信公众号:每天晒白牙关注可了解更多编程知识。问题或建议,请公众号留言;如果你觉得文章对你有帮助,欢迎关注与转发题目描述给定一个包含m*n

微信公众号:每天晒白牙
关注可了解更多编程知识。问题或建议,请公众号留言;如果你觉得文章对你有帮助,欢迎关注与转发

题目描述

给定一个包含 m*n 个元素的矩阵(m 行,n 列),请按顺时针螺旋顺序,返回矩阵中所有元素

leetcode 第 54 题

https://leetcode-cn.com/problems/spiral-matrix/

示例

示例 1

输入:
[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]
输出: [1,2,3,6,9,8,7,4,5]

示例 2

输入:
[
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9,10,11,12]
]
输出: [1,2,3,4,8,12,11,10,9,5,6,7]

分析

方法 1 :模拟遍历

通过示例,我们可以很清晰的知道螺旋矩阵的遍历过程,所以方法 1 中就采用模拟遍历的方法

首先,我们需要定义行和列的方向数组,因为当遍历到矩阵的边界需要换方向。同时遍历到已经遍历过的元素时也需要换方向,不然就一直在最外层转圈了,后面会解释

行的方向数组 int[] dr = {0, 1, 0, -1}

列的方向数组 int[] dc = {1, 0, -1, 0}

下面分别解释下

行方向向量解释
0往右遍历
1往下遍历
0往左遍历
-1往上遍历
列方向向量解释
1往右遍历
0往下遍历
-1往左遍历
0往上遍历

有了方向向量,还需要有个二维数组记录已经遍历过的元素坐标 (row,column) ,如果遍历过,该坐标对应的值就是 true

boolean[][] seen = new boolean[row][column]

在做边界的判断的同时也要判断元素是否被访问过,不然不然就一直在最外层转圈了。我们拿示例 1 举例子,当遍历到元素 4 时,如果此时不对已经遍历过的元素进行判断,下一步就会遍历 1,而不是 5,如下图所示:

ba9348a192dc7a8cd85b2842e245fe3a.png

对已经遍历过的元素进行判断

源码

public static List spiralOrder(int[][] matrix) {
        if (matrix.length == 0) {
            return new ArrayList();
        }
        int row = matrix.length;
        int column = matrix[0].length;

        List result = new ArrayList(row * column);

        // 方向数组
        // 行方向 0:右,1:下,0:左,-1:上
        int[] dr = {0,1,0,-1};
        // 列方向 1: 右,0:下,-1:左,0:上
        int[] dc = {1,0,-1,0};
        int r = 0, c = 0, di = 0;

        // 标记第 r 行 c 列的单元素被访问过了
        boolean[][] seen = new boolean[row][column];

        // 遍历整个二维数组即矩阵
        for (int i = 0; i             // 将下标对应的元素放到结果集中
            result.add(matrix[r][c]);
            // 标记 r 行 c 列的元素被访问过了,这个判断主要用在要换圈的时候,因为如果没有这个限制,它就不会缩小圈
            seen[r][c] = true;
            // 下一步移动的候选位置
            int nr = r + dr[di];
            int nc = c + dc[di];

            // 做边界与是否已经访问过的判断
            if (nr >= 0 && nr = 0 && nc                 r = nr;
                c = nc;
            } else {
                // 说明到了边界了,需要换方向了
                di = (di + 1) % 4;
                r = r + dr[di];
                c = c + dc[di];
            }
        }
        return result;
    }

执行结果

b22f6fca349d117b2d91ca86cacf19f3.png

方法1执行结果

复杂度分析

时间复杂度:O(n),需要遍历矩阵中所有的元素

空间复杂度:O(n),需要用到数组 seen 和 result

方法 2:按层(圈)遍历

我们把这个矩阵像剥洋葱似的一层一层的剥开,从最外层一直到最里层,我们通过示例图看下流程

09a48de2fd8a404e8e640a7c3a43e9be.png

方法2流程分析

这个方法理解起来比较简单,值得需要注意的一点是对当前层是否有 4 条边的判断即 rowMin

源码

public static List spiralOrder3(int[][] matrix) {
        if (matrix.length == 0) {
            return new ArrayList();
        }
        // rowMin 表示当前层行的最小下标 rowMax 表示当前层行的最大下标
        int rowMin = 0, rowMax = matrix.length - 1;
        // columnMin 表示当前层列的最小下标 columnMax 表示当前层列的最大下标
        int columnMin = 0, columnMax = matrix[0].length - 1;
        // (rowMin,columnMin) 代表当前层的左上角的坐标  (rowMax,columnMax) 表示当前层右下角的坐标
        List result = new ArrayList(matrix.length * matrix[0].length);

        while (rowMin <&#61; rowMax && columnMin <&#61; columnMax) {
            // 遍历当前层的上面边的所有元素 行坐标不变&#xff0c;列坐标 column 从 columnMin 到 columnMax
            for (int column &#61; columnMin; column <&#61; columnMax; column&#43;&#43;) {
                result.add(matrix[rowMin][column]);
            }
            // 遍历当前层的右面边的所有元素 列坐标不变&#xff0c;行坐标 row 从 rowMin &#43; 1 到 rowMax
            for (int row &#61; rowMin &#43; 1; row <&#61; rowMax; row&#43;&#43;) {
                result.add(matrix[row][columnMax]);
            }
            // 如果当前层有 4 条边即满足条件 rowMin if (rowMin                 // 遍历当前层的下面边的所有元素 行坐标不变&#xff0c;列坐标从 columnMax -1 到 columnMinfor (int column &#61; columnMax - 1; column >&#61; columnMin; column--) {
                    result.add(matrix[rowMax][column]);
                }// 遍历当前层左面边的所有元素 列坐标不变&#xff0c;行坐标从 rowMax -1  遍历到 rowMin &#43; 1for (int row &#61; rowMax - 1; row > rowMin; row--) {
                    result.add(matrix[row][columnMin]);
                }
            }// 遍历一层后&#xff0c;遍历下一层&#xff0c;需要更新 rowMin、rowMax、columnMin、columnMax 的坐标
            rowMin&#43;&#43;;
            rowMax--;
            columnMin&#43;&#43;;
            columnMax--;
        }return result;
    }

执行结果

96bde4fb60871aa3c9cd0c5b7c61014c.png

方法2执行结果

复杂度分析

时间复杂度&#xff1a;O(n)&#xff0c;需要遍历矩阵中所有的元素

空间复杂度&#xff1a;O(n)&#xff0c;需要用到 result

用过该题作为面试题的公司

9530216e86a5835a1bcac148c53a7db9.png

推荐阅读

原创|如果懂了HashMap这两点&#xff0c;面试就没问题了

面试官:如何用最少的老鼠试出有毒的牛奶&#xff1f;

cpu使用率过高和jvm old占用过高排查过程

老年代又占用100%了&#xff0c;顺便发现了vertx-redis-client 的bug

KafkaProducer源码分析

Kafka服务端之网络层源码分析

Redis 的过期策略是如何实现的&#xff1f;

原创|面试官&#xff1a;Java对象一定分配在堆上吗&#xff1f;

ThreadPoolExecutor 线程池"源码分析"

类加载器知识点吐血整理

三面阿里被挂&#xff0c;幸获内推名额&#xff0c;历经 5 面终获口碑 offer

原创|ES广告倒排索引架构演进与优化

广告倒排索引架构与优化

频繁FGC的真凶原来是它

原创|这道面试题&#xff0c;大部分人都答错了

同事:把"重试"抽象出来做个工具类吧



推荐阅读
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 开发笔记:Java是如何读取和写入浏览器Cookies的
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java是如何读取和写入浏览器Cookies的相关的知识,希望对你有一定的参考价值。首先我 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 从零学Java(10)之方法详解,喷打野你真的没我6!
    本文介绍了从零学Java系列中的第10篇文章,详解了Java中的方法。同时讨论了打野过程中喷打野的影响,以及金色打野刀对经济的增加和线上队友经济的影响。指出喷打野会导致线上经济的消减和影响队伍的团结。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • Java程序设计第4周学习总结及注释应用的开发笔记
    本文由编程笔记#小编为大家整理,主要介绍了201521123087《Java程序设计》第4周学习总结相关的知识,包括注释的应用和使用类的注释与方法的注释进行注释的方法,并在Eclipse中查看。摘要内容大约为150字,提供了一定的参考价值。 ... [详细]
  • 本文介绍了Java中Hashtable的clear()方法,该方法用于清除和移除指定Hashtable中的所有键。通过示例程序演示了clear()方法的使用。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 一次上线事故,30岁+的程序员踩坑经验之谈
    本文主要介绍了一位30岁+的程序员在一次上线事故中踩坑的经验之谈。文章提到了在双十一活动期间,作为一个在线医疗项目,他们进行了优惠折扣活动的升级改造。然而,在上线前的最后一天,由于大量数据请求,导致部分接口出现问题。作者通过部署两台opentsdb来解决问题,但读数据的opentsdb仍然经常假死。作者只能查询最近24小时的数据。这次事故给他带来了很多教训和经验。 ... [详细]
  • 本文整理了Java中java.lang.NoSuchMethodError.getMessage()方法的一些代码示例,展示了NoSuchMethodErr ... [详细]
author-avatar
鱼儿什么都知道丶
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有