LeetCode hot 100 每日一题(14)——54.螺旋矩阵
这是一道难度为中等的题目,让我们来看看题目描述:
给你一个
m
行n
列的矩阵matrix
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 10
-100 <= matrix[i][j] <= 100
题解
解题的核心思路是按照右、下、左、上的顺序遍历数组,并使用四个变量圈定未遍历元素的边界:
随着螺旋遍历,相应的边界会收缩,直到螺旋遍历完整个数组:
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
// 获取矩阵的行数和列数
int m = matrix.length; // 行数
int n = matrix[0].length; // 列数
// 定义遍历未处理区域的边界:
// upper_bound:上边界,初始为第一行(索引0)
// lower_bound:下边界,初始为最后一行(索引 m - 1)
int upper_bound = 0, lower_bound = m - 1;
// left_bound:左边界,初始为第一列(索引0)
// right_bound:右边界,初始为最后一列(索引 n - 1)
int left_bound = 0, right_bound = n - 1;
// 创建一个链表用来保存最终的螺旋顺序遍历结果
List<Integer> res = new LinkedList<>();
// 当结果列表的元素个数还没有达到整个矩阵的元素总数时,继续遍历
while (res.size() < m * n) {
// 从左到右遍历上边界这一行
// 前提条件:upper_bound <= lower_bound确保当前行未超出下边界
if (upper_bound <= lower_bound) {
for (int j = left_bound; j <= right_bound; j++) {
res.add(matrix[upper_bound][j]); // 将上边界行的元素依次添加
}
upper_bound++; // 上边界向下移动一行,因为当前行已遍历
}
// 从上到下遍历右边界这一列
// 前提条件:left_bound <= right_bound确保当前列未超出左边界
if (left_bound <= right_bound) {
for (int i = upper_bound; i <= lower_bound; i++) {
res.add(matrix[i][right_bound]); // 将右边界列的元素依次添加
}
right_bound--; // 右边界向左移动一列,因为当前列已遍历
}
// 从右到左遍历下边界这一行
// 前提条件:upper_bound <= lower_bound确保当前行未超出上边界
if (upper_bound <= lower_bound) {
for (int j = right_bound; j >= left_bound; j--) {
res.add(matrix[lower_bound][j]); // 将下边界行的元素依次添加
}
lower_bound--; // 下边界向上移动一行,因为当前行已遍历
}
// 从下到上遍历左边界这一列
// 前提条件:left_bound <= right_bound确保当前列未超出右边界
if (left_bound <= right_bound) {
for (int i = lower_bound; i >= upper_bound; i--) {
res.add(matrix[i][left_bound]); // 将左边界列的元素依次添加
}
left_bound++; // 左边界向右移动一列,因为当前列已遍历
}
}
// 返回包含所有元素的螺旋顺序结果列表
return res;
}
}
总结
这道题目的解法对我来说有一些难以理解,那么直接强制记忆:
你可以试着将这个螺旋遍历过程拆分成四个简单的步骤,每一步只关注一个方向,并记住一个顺时针的遍历顺序:从左到右、从上到下、从右到左、从下到上。下面几个记忆小技巧可能对你有帮助:
-
分块记忆:
想象矩阵就像一层层的“洋葱皮”。每一层的遍历就是围绕这个“洋葱”走一圈,你只需要记住当前层的边界,然后按照顺时针方向依次执行四个步骤。 -
口诀法:
你可以编一个简单的口诀,比如“左到右,上到底,右到左,下到上”。每完成一圈后,再调整边界,重复这个过程。 -
边界的概念:
四个变量(upper_bound、lower_bound、left_bound、right_bound)就像四道“防线”。每次遍历一条边之后,你就“消耗”掉这一行或这一列,然后更新边界。记住:-
遍历上边界后,upper_bound++
-
遍历右边界后,right_bound–
-
遍历下边界后,lower_bound–
-
遍历左边界后,left_bound++
-
-
可视化思维:
在心里或纸上画出一个矩阵,并用箭头标注出遍历的方向。通过不断的练习,你会发现这种螺旋移动方式会越来越直观。