LeetCode 54中等矩阵 · 边界收缩
螺旋矩阵 图解题解
这道题到底在问什么
按顺时针螺旋顺序返回矩阵中的所有元素。
- matrix
- [[1,2,3],[4,5,6],[7,8,9]]
- 输出
- [1,2,3,6,9,8,7,4,5]
最优解:一步一步想明白
- 3关键不是背模板,而是看懂为什么这题适合矩阵 · 边界收缩。
- 4用 top / bottom / left / right 四条边界框住「还没走的区域」,按 右→下→左→上 顺时针走,走完一条边就把它向内收一格。
- 5沿 top 行从左到右走:1, 2, 3。走完 top 下移一格(top=1)。
- 6沿 right 列从上到下走:6, 9。走完 right 左移一格(right=1)。
- 7沿 bottom 行从右到左走:8, 7。走完 bottom 上移一格(bottom=1)。
- 8沿 left 列从下到上走:4。走完 left 右移一格(left=1)。
- 9四条边界一路向内收缩,最后只剩中心 5。顺时针螺旋输出 = [1,2,3,6,9,8,7,4,5]。
- 12把这句话记住,下次遇到同类题,就能更快选出方向。
⚠️ 容易写错的地方
✗ 错:每走完一边不更新边界
✓ 对:走完一条边就收缩对应边界
否则会重复访问
✗ 错:单行/单列时下边、左边又走一遍
✓ 对:走下边前判 top<=bottom、走左边前判 left<=right
扁矩阵里上边和下边可能是同一行,不judge会重复收集。
✗ 错:变量名和动画不一致
✓ 对:代码变量沿用动画里的核心名字
学习时最怕脑内维护两套概念
完整代码(Python / C++ / Java)
Python
class Solution:
def spiralOrder(self, matrix):
ans = []
top, bottom = 0, len(matrix) - 1
left, right = 0, len(matrix[0]) - 1
while top <= bottom and left <= right:
for c in range(left, right + 1): ans.append(matrix[top][c])
top += 1
for r in range(top, bottom + 1): ans.append(matrix[r][right])
right -= 1
if top <= bottom:
for c in range(right, left - 1, -1): ans.append(matrix[bottom][c])
bottom -= 1
if left <= right:
for r in range(bottom, top - 1, -1): ans.append(matrix[r][left])
left += 1
return ansC++
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> ans;
int top = 0, bottom = matrix.size() - 1;
int left = 0, right = matrix[0].size() - 1;
while (top <= bottom && left <= right) {
for (int c = left; c <= right; c++) ans.push_back(matrix[top][c]);
top++;
for (int r = top; r <= bottom; r++) ans.push_back(matrix[r][right]);
right--;
if (top <= bottom) {
for (int c = right; c >= left; c--) ans.push_back(matrix[bottom][c]);
bottom--;
}
if (left <= right) {
for (int r = bottom; r >= top; r--) ans.push_back(matrix[r][left]);
left++;
}
}
return ans;
}
};Java
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> ans = new ArrayList<>();
int top = 0, bottom = matrix.length - 1;
int left = 0, right = matrix[0].length - 1;
while (top <= bottom && left <= right) {
for (int c = left; c <= right; c++) ans.add(matrix[top][c]);
top++;
for (int r = top; r <= bottom; r++) ans.add(matrix[r][right]);
right--;
if (top <= bottom) {
for (int c = right; c >= left; c--) ans.add(matrix[bottom][c]);
bottom--;
}
if (left <= right) {
for (int r = bottom; r >= top; r--) ans.add(matrix[r][left]);
left++;
}
}
return ans;
}
}套路模板 · 矩阵 · 边界收缩
# 螺旋矩阵骨架 · 四边界收缩
top, bottom, left, right = 0, m-1, 0, n-1
while top <= bottom and left <= right:
走上边 left→right; top += 1
走右边 top→bottom; right -= 1
if top <= bottom: # 防扁矩阵重复走下边
走下边 right→left; bottom -= 1
if left <= right: # 防瘦矩阵重复走左边
走左边 bottom→top; left += 1复杂度
时间复杂度
O(mn)
每个格子恰好被走一次,共 m×n 个
空间复杂度
O(1)
只用 top/bottom/left/right 四个边界变量,迭代无递归栈(不计输出数组)
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 螺旋矩阵 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么每走完一边要先收缩再判断?+
防止单行/单列重复访问;收缩后用 top<=bottom / left<=right 判断是否还有剩余行列。
用方向数组+visited 行吗?+
行,碰到边界或已访问就转向;但四边界法更直观。
复杂度?+
O(m·n) 每个元素访问一次。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。