LeetCode54 螺旋矩阵,题目不重要,重要的是这个技巧

2024-03-21 14:32

本文主要是介绍LeetCode54 螺旋矩阵,题目不重要,重要的是这个技巧,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文始发于个人公众号:TechFlow,原创不易,求个关注


今天是LeetCode专题的第32篇文章,我们一起看的是LeetCode的第54题——Spiral Matrix。

首先解释一下题意,这个Spiral是螺旋的意思,据说英文版的漫画里,把鸣人的螺旋丸就翻译成Spiral Sphere…

走远了,回归正传。通过螺旋丸我们都知道螺旋形是什么意思,所以所谓的螺旋矩阵,就是按照螺旋形的顺序来遍历一个数组,或者说矩阵。我们可以看下下图:

箭头标注的顺序就是螺旋的顺序,这道题让我们求的就是按照螺旋的顺序遍历之后的结果。

背景

这道题的题意非常简单,我想大家肯定都能看明白,但是真的要上手去做会发现还是蛮困难的。主要的难点就是我们遍历的顺序一直在变化,并且变化的速度也是在变化的。虽然从某种程度上来说,这些变化都是有迹可循的,但是即便如此,把这些规律抽象出来写成简单易懂没有bug的代码也并不是一件容易的事情。

如果我没有记错的话,当年我大二的时候学校里的acm校赛有一题就是这个,一模一样的原题。虽然非常简单,每个人都知道怎么做,但是最后的通过率并不高。

这并不完全是出题人的恶意,其实这类问题在acm的比赛当中还是很常见的。经常会有一些题目很清晰明确,你只需要照着实现就可以了的题目。考察的就是选手的抽象和编码能力,虽然题意不难,但是在比赛高压的场景下想要快速写出一个几百行包含一系列复杂逻辑的程序并且没有bug,还是非常困难的一件事。由于这类题目的关键就是让我们模拟出来题目的意思,所以也被称为模拟题。

想要比较顺手地写出这道题,需要一个很常用的技巧或者说惯例,这也是这篇文章的关键。

方向数组

在许多问题当中我们经常会遇到这样一个问题,比如我们需要遍历一个迷宫,需要沿着现实世界当中上下左右或者是东南西北的方向进行移动。在移动的过程当中自然就涉及各种各样的方向,于是我们需要用代码来表示方向。

比如我们画一个小人,它所在的坐标是(x, y),它有东南西北四个方向可以选。我们假设他每次移动一个单位的距离,我们很容易就得出它往各个方向移动之后的新坐标。

根据数学上向量的定义,我们可以写出这四个方向的方向单位向量:[0, 1], [0, -1], [1, 0], [-1, 0]。

我们把这些向量存放进一个常量数组当中,就得到了方向数组。当我们需要遍历所有方向的时候,我们只需要遍历这个数组即可。

不仅如此,如果我们对方向的遍历顺序有要求,它也完全可以实现。比如在这题当中,我们可以发现,螺旋遍历每一次改变顺序其实都是向左转了90度

原本朝东的旋转之后变成了朝南,朝南的变成了朝西,朝西的成了朝北,而朝北的成了朝东。那么我们只需要把方向按照东南西北的顺序摆放,我们每次把方向数组的下标增加一位并对4取模,就得到了下一个方向。

这个技巧并不难理解,但是可以大大简化我们的代码。

解答

理解了方向数组之后剩下的就容易多了,我们观察一下上面螺旋遍历的过程,每一次改变方向遍历的长度虽然不同,但是每一次改变的原因是一致的,就是这个方向上已经遍历到头了,所以我们需要变更方向。明白了这点其实就很容易了,我们只需要维护每个方向上的终点,每次到终点则进行变向。由于矩阵当中元素的数量是固定的,我们遍历的次数也就知道了,所以只要把变更方向的事情处理好,这道题也就解决了。

我们来看下代码:

class Solution:def spiralOrder(self, matrix: List[List[int]]) -> List[int]:# 定义方向数组fx = [[0, 1], [1, 0], [0, -1], [-1, 0]]n = len(matrix)if n == 0:return []m = len(matrix[0])ret = []# 定义边界数组# 边界数组和旋转的顺序也是对应的# 第一次旋转之后上边界+1,所以第0位是上边界# 第二次旋转之后,右边界-1# 以此类推condition = [0, m-1, n-1, 0]x, y, dt = 0, 0, 0for i in range(n * m):ret.append(matrix[x][y])x_, y_ = x + fx[dt][0], y + fx[dt][1]# 如果已经越过边界了,则需要转向if x_ < condition[0] or x_ > condition[2] or y_ < condition[3] or y_ > condition[1]:# 更新边界if dt in (1, 2):condition[dt] -= 1else:condition[dt] += 1# 转向,并且重新移动dt = (dt + 1) % 4x_, y_ = x+fx[dt][0], y+fx[dt][1]# print(x_, y_)x, y = x_, y_return ret

我们观察一下代码,还有一个我们刚才没有提到的细节。我们在移动的时候,并不是直接在原变量上进行变更,因为如果一旦移动超界或者触发其他非法的情况,那么我们就无法回滚了。所以我们会创建新的x和y的变量来表示移动之后的位置,即使移动到了非法位置,也不会影响之前的结果。这也是一个常用的技巧,在Python当中,我们在变量末尾加上下划线表示这是一个影子(克隆)变量。

总结

我个人认为今天的题目出得不错,初学者很有必要亲自动手做一下。因为在做题的过程当中我们可以很具体地学到方向数组这个很有用的解题技巧,它在搜索问题当中广泛使用,可以说是做算法题必须会的技巧之一。

可能你会觉得我们通过边界判断是否需要转向的逻辑看起来有些复杂,这并不是必须的。我们也可以使用一些其他方法来代替,比如我们可以开辟一个数组记录已经遍历过的位置来代替边界的判定,和使用边界判定的方法相比,这样做消耗的空间要更大一些,并且通过边界判定的方法更加考验思维一些,因此我个人比较推荐。当然,这题还有一些其他的方法,比如找规律什么的,不是特别巧妙,就不占用大家时间了。

今天的文章就是这些,如果觉得有所收获,请顺手点个关注或者转发吧,你们的举手之劳对我来说很重要。

在这里插入图片描述

这篇关于LeetCode54 螺旋矩阵,题目不重要,重要的是这个技巧的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/832897

相关文章

Java 枚举的常用技巧汇总

《Java枚举的常用技巧汇总》在Java中,枚举类型是一种特殊的数据类型,允许定义一组固定的常量,默认情况下,toString方法返回枚举常量的名称,本文提供了一个完整的代码示例,展示了如何在Jav... 目录一、枚举的基本概念1. 什么是枚举?2. 基本枚举示例3. 枚举的优势二、枚举的高级用法1. 枚举

不删数据还能合并磁盘? 让电脑C盘D盘合并并保留数据的技巧

《不删数据还能合并磁盘?让电脑C盘D盘合并并保留数据的技巧》在Windows操作系统中,合并C盘和D盘是一个相对复杂的任务,尤其是当你不希望删除其中的数据时,幸运的是,有几种方法可以实现这一目标且在... 在电脑生产时,制造商常为C盘分配较小的磁盘空间,以确保软件在运行过程中不会出现磁盘空间不足的问题。但在

如何评价Ubuntu 24.04 LTS? Ubuntu 24.04 LTS新功能亮点和重要变化

《如何评价Ubuntu24.04LTS?Ubuntu24.04LTS新功能亮点和重要变化》Ubuntu24.04LTS即将发布,带来一系列提升用户体验的显著功能,本文深入探讨了该版本的亮... Ubuntu 24.04 LTS,代号 Noble NumBAT,正式发布下载!如果你在使用 Ubuntu 23.

Python中列表的高级索引技巧分享

《Python中列表的高级索引技巧分享》列表是Python中最常用的数据结构之一,它允许你存储多个元素,并且可以通过索引来访问这些元素,本文将带你深入了解Python列表的高级索引技巧,希望对... 目录1.基本索引2.切片3.负数索引切片4.步长5.多维列表6.列表解析7.切片赋值8.删除元素9.反转列表

Python中处理NaN值的技巧分享

《Python中处理NaN值的技巧分享》在数据科学和数据分析领域,NaN(NotaNumber)是一个常见的概念,它表示一个缺失或未定义的数值,在Python中,尤其是在使用pandas库处理数据时,... 目录NaN 值的来源和影响使用 pandas 的 isna()和 isnull()函数直接比较 Na

Oracle数据库执行计划的查看与分析技巧

《Oracle数据库执行计划的查看与分析技巧》在Oracle数据库中,执行计划能够帮助我们深入了解SQL语句在数据库内部的执行细节,进而优化查询性能、提升系统效率,执行计划是Oracle数据库优化器为... 目录一、什么是执行计划二、查看执行计划的方法(一)使用 EXPLAIN PLAN 命令(二)通过 S

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

购买磨轮平衡机时应该注意什么问题和技巧

在购买磨轮平衡机时,您应该注意以下几个关键点: 平衡精度 平衡精度是衡量平衡机性能的核心指标,直接影响到不平衡量的检测与校准的准确性,从而决定磨轮的振动和噪声水平。高精度的平衡机能显著减少振动和噪声,提高磨削加工的精度。 转速范围 宽广的转速范围意味着平衡机能够处理更多种类的磨轮,适应不同的工作条件和规格要求。 振动监测能力 振动监测能力是评估平衡机性能的重要因素。通过传感器实时监

滚雪球学Java(87):Java事务处理:JDBC的ACID属性与实战技巧!真有两下子!

咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java SE啦,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~ 🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!! 环境说明:Windows 10

hdu 4565 推倒公式+矩阵快速幂

题意 求下式的值: Sn=⌈ (a+b√)n⌉%m S_n = \lceil\ (a + \sqrt{b}) ^ n \rceil\% m 其中: 0<a,m<215 0< a, m < 2^{15} 0<b,n<231 0 < b, n < 2^{31} (a−1)2<b<a2 (a-1)^2< b < a^2 解析 令: An=(a+b√)n A_n = (a +