题目描述
思路解析动画文字版
记住两根尺子:方向东南西北转圈,步长每两段加一。下面用一张小网格把这两根尺子走一遍。
网格总览 · 起点 (1,1):看这张图。真正的网格是上面绿框这两行,共 2 行 4 列。最下面一条灰带代表「网格外面」,等会儿螺旋会踩进去。绿色的 (1,1) 是起点,先把它记成答案里的第 1 个。
步长规律 · 1,1,2,2,3,3:先把步长规律记牢。出发先向东走 1 步,再向南走 1 步;然后向西走 2 步,向北走 2 步;接着向东走 3 步,向南走 3 步。就是每两段用同一个步长,走完两段步长就加一。
向东走 · 落到 (1,2):出发了。第一段向东走 1 步,指针落到 (1,2)(橙色)。每走到一格,先问一句:这格在网格里吗?
在界内 · 记成第 2 个:(1,2) 的行和列都没越界,在网格里。把它涂绿、记成答案的第 2 个,右边 ans 队伍多了一个坐标。
向南走 · 落到 (2,2):指针沿着南方向迈一步,落到 (2,2)。还是老规矩,先判断它在不在真实网格里。
在界外 · 照走但不记:(2,2) 掉到灰带里,也就是网格外面。这一步照样要走,但不能记进答案,所以打个红叉跳过。注意:虽然没记,人还是站在这里继续往前走。
向西走 · 落到 (2,1):指针沿着西方向迈一步,落到 (2,1)。还是老规矩,先判断它在不在真实网格里。
在界外 · 照走但不记:(2,1) 又是界外,继续打叉跳过,ans 不变,但脚步不停,接着按规律往下走。
向西走 · 落到 (2,0):指针沿着西方向迈一步,落到 (2,0)。还是老规矩,先判断它在不在真实网格里。
在界外 · 照走但不记:(2,0) 又是界外,继续打叉跳过,ans 不变,但脚步不停,接着按规律往下走。
向北走 · 落到 (1,0):指针沿着北方向迈一步,落到 (1,0)。还是老规矩,先判断它在不在真实网格里。
在界内 · 记成第 3 个:(1,0) 的行和列都没越界,在网格里。把它涂绿、记成答案的第 3 个,右边 ans 队伍多了一个坐标。
向北走 · 落到 (0,0):指针沿着北方向迈一步,落到 (0,0)。还是老规矩,先判断它在不在真实网格里。
在界内 · 记成第 4 个:(0,0) 同样在界内,收进答案,成为第 4 个。
向东走 · 落到 (0,1):指针沿着东方向迈一步,落到 (0,1)。还是老规矩,先判断它在不在真实网格里。
在界内 · 记成第 5 个:(0,1) 同样在界内,收进答案,成为第 5 个。
向东走 · 落到 (0,2):指针沿着东方向迈一步,落到 (0,2)。还是老规矩,先判断它在不在真实网格里。
在界内 · 记成第 6 个:(0,2) 同样在界内,收进答案,成为第 6 个。
向东走 · 落到 (0,3):指针沿着东方向迈一步,落到 (0,3)。还是老规矩,先判断它在不在真实网格里。
在界内 · 记成第 7 个:(0,3) 同样在界内,收进答案,成为第 7 个。
向南走 · 落到 (1,3):指针沿着南方向迈一步,落到 (1,3)。还是老规矩,先判断它在不在真实网格里。
在界内 · 记成第 8 个:(1,3) 同样在界内,收进答案,成为第 8 个。
收集完毕 · 共 8 个格子:当记录数等于网格总格数 8,就说明全走遍了,立刻收工。右边 ans 这一长串坐标,正是按螺旋访问顺序排好的最终答案。中间踩进灰带的那几步,一个都没混进来。
边界先想清:单格直接返回、单行只有东向有效、起点贴边时头几步常落界外。
两个高频追问:计数器代替 visited 数组省空间;界外空走是平方级、规模内完全可接受。
参考代码
from __future__ import annotationsfrom typing import *from collections import *from functools import *from itertools import *from math import *from heapq import *from bisect import *class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = rightclass ListNode: def __init__(self, val=0, next=None): self.val = val self.next = nextclass Solution: def spiralMatrixIII( self, rows: int, cols: int, rStart: int, cStart: int ) -> List[List[int]]: ans = [[rStart, cStart]] if rows * cols == 1: return ans k = 1 while True: for dr, dc, dk in [[0, 1, k], [1, 0, k], [0, -1, k + 1], [-1, 0, k + 1]]: for _ in range(dk): rStart += dr cStart += dc if 0 <= rStart < rows and 0 <= cStart < cols: ans.append([rStart, cStart]) if len(ans) == rows * cols: return ans k += 2复杂度
- 时间:O(max(rows, cols)²),螺旋边长一圈圈变大,含界外空走的步数与最长边的平方同阶
- 空间:O(rows · cols),只有答案列表本身的开销,不算它则是 O(1) 的额外变量
易错点
面试追问把动画讲成自己的话
追问为什么不开一个二维 visited 数组来标记走过的格子?
追问界外空走会不会让时间复杂度爆掉?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
可能的二分法
LeetCode 886 · 中等 · 沿着 图论套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题