目录
题目
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
解法
这是一个经典的螺旋矩阵问题。你可以使用 C++ 来解决,通过依次遍历矩阵的边界,然后逐步缩小矩阵的范围。代码如下:
#include <iostream>
#include <vector>
using namespace std;
vector<int> spiralOrder(vector<vector<int>>& matrix) {
if (matrix.empty()) return {};
vector<int> result;
int m = matrix.size();
int n = matrix[0].size();
int left = 0, right = n - 1, top = 0, bottom = m - 1;
while (left <= right && top <= bottom) {
// 从左到右遍历上边界
for (int i = left; i <= right; ++i) {
result.push_back(matrix[top][i]);
}
top++; // 上边界向下收缩
// 从上到下遍历右边界
for (int i = top; i <= bottom; ++i) {
result.push_back(matrix[i][right]);
}
right--; // 右边界向左收缩
if (top <= bottom) {
// 从右到左遍历下边界
for (int i = right; i >= left; --i) {
result.push_back(matrix[bottom][i]);
}
bottom--; // 下边界向上收缩
}
if (left <= right) {
// 从下到上遍历左边界
for (int i = bottom; i >= top; --i) {
result.push_back(matrix[i][left]);
}
left++; // 左边界向右收缩
}
}
return result;
}
int main() {
vector<vector<int>> matrix = {{1, 2, 3},
{4, 5, 6},
{7, 8, 9}};
vector<int> result = spiralOrder(matrix);
for (int num : result) {
cout << num << " ";
}
return 0;
}
代码说明:
spiralOrder
函数接受一个二维矩阵作为输入,并返回按照螺旋顺序排列的矩阵元素的列表。- 定义四个边界:
left
、right
、top
和bottom
,分别表示矩阵的左、右、上、下边界。 - 使用
while
循环依次遍历边界,首先从左到右遍历上边界,然后从上到下遍历右边界,接着从右到左遍历下边界,最后从下到上遍历左边界。 - 每次遍历完一圈后,相应地收缩边界,直到不再满足条件。
输出结果:
对输入矩阵 {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
,输出将为:
1 2 3 6 9 8 7 4 5
这种方法的时间复杂度为 O(m * n),其中 m 是矩阵的行数,n 是矩阵的列数。
如何螺旋地来遍历矩阵?
result.push_back()
result.push_back() 是 C++ 标准库中 std::vector 容器的方法之一,用于将一个元素添加到 vector 的末尾。
有点像append
矩阵的大小如何获取?
int m = matrix.size();
int n = matrix[0].size();
相当于获取两个数组的长度,行列
这道题的关键点?
这道“螺旋矩阵”题的关键点在于如何按照正确的顺序遍历矩阵的所有元素。具体而言,有几个重要的逻辑点需要关注:
关键点 1:边界收缩的策略
在螺旋顺序遍历过程中,矩阵的边界不断收缩。为了确保我们遍历所有元素并避免重复,需要明确处理好四个边界:
- 上边界 (
top
):从左到右遍历上边界的元素后,收缩上边界,top++
。 - 右边界 (
right
):从上到下遍历右边界的元素后,收缩右边界,right--
。 - 下边界 (
bottom
):从右到左遍历下边界的元素后,收缩下边界,bottom--
。 - 左边界 (
left
):从下到上遍历左边界的元素后,收缩左边界,left++
。
关键点 2:循环停止条件
我们需要在遍历的过程中确保不会越界,尤其在矩阵的某一边已经收缩到尽头时,不能再继续访问该边的元素。因此,循环的停止条件是当左边界超过右边界或者上边界超过下边界时,说明已经遍历完所有元素,此时退出循环。
关键点 3:遍历的方向
螺旋顺序本质上是遵循一个 顺时针的方向,因此需要依次遍历:
- 从左到右 遍历上边界。
- 从上到下 遍历右边界。
- 从右到左 遍历下边界(在确保上边界依然小于等于下边界的前提下)。
- 从下到上 遍历左边界(在确保左边界依然小于等于右边界的前提下)。
每一次完成一圈后,边界收缩,进入下一圈的遍历。
关键点 4:处理不同形状的矩阵
矩阵的形状可能不同,例如:
- 行数多于列数,或者列数多于行数。
- 矩阵为奇数行列或偶数行列。
因此,代码中的边界判断 (if
语句) 和循环控制必须能处理任意形状的矩阵,确保不会多次访问某个已经遍历过的元素。
关键点 5:时间复杂度
遍历矩阵的过程中,每个元素只会被访问一次,因此时间复杂度为 ( O(m \times n) ),其中 ( m ) 是矩阵的行数,( n ) 是矩阵的列数。这个复杂度是最优的,因为我们必须访问矩阵中的每个元素。
总结
螺旋矩阵问题的关键在于:
- 正确的边界收缩逻辑。
- 循环停止条件的控制。
- 按照顺时针方向分段遍历矩阵。
- 对不同形状矩阵的处理。