LeetCode算法刷题——54. 螺旋矩阵

一、题目描述

二、解题思路

我们使用边界收缩法来解决这个问题:

  1. 定义四个边界:上边界(u)、下边界(d)、左边界(l)、右边界(r)

  2. 按照顺时针方向遍历:右→下→左→上

  3. 每完成一个方向的遍历,就收缩相应的边界

  4. 重复直到所有元素都被遍历

三、完整代码

cpp

复制代码
class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> rst;
        int rol = matrix.size(), col = matrix[0].size();  // 获取矩阵行列数
        int l = 0, r = col - 1, u = 0, d = rol - 1;      // 初始化边界
        
        while (l <= r && u <= d) {
            // 从左到右遍历上边界
            for (int j = l; j <= r; j++) {
                rst.push_back(matrix[u][j]);
            }
            u++;  // 上边界下移
            
            // 从上到下遍历右边界
            for (int j = u; j <= d; j++) {
                rst.push_back(matrix[j][r]);
            }
            r--;  // 右边界左移
            
            // 从右到左遍历下边界(需要检查是否还有行)
            if (u <= d) {
                for (int j = r; j >= l; j--) {
                    rst.push_back(matrix[d][j]);
                }
                d--;  // 下边界上移
            }
            
            // 从下到上遍历左边界(需要检查是否还有列)
            if (l <= r) {
                for (int j = d; j >= u; j--) {
                    rst.push_back(matrix[j][l]);
                }
                l++;  // 左边界右移
            }
        }
        
        return rst;
    }
};

四、代码解析

1. 获取矩阵行列数

int rol = matrix.size(), col = matrix[0].size();

  • matrix.size():返回二维向量的行数(row count)

    • matrix 是一个 vector<vector<int>>,每个元素是一个 vector<int>(一行)

    • matrix.size() 返回外层向量的大小,即矩阵的行数

  • matrix[0].size() :返回第一行的列数(column count)

    • matrix[0] 是第一行的向量(索引为0)

    • matrix[0].size() 返回该向量的元素个数,即矩阵的列数

2. 边界初始化

复制代码
int l = 0, r = col - 1, u = 0, d = rol - 1;

利于后续直接行列索引定位!

  • l:当前未遍历的最左列索引

  • r:当前未遍历的最右列索引

  • u:当前未遍历的最上行索引

  • d:当前未遍历的最下行索引

3. 整体循环条件

while (l <= r && u <= d)

  • l <= r:还有列需要遍历

  • u <= d:还有行需要遍历

  • 两者都满足时,矩阵中还有元素未遍历

4. 顺时针遍历详细说明

第一方向:从左到右(上边界)

for (int j = l; j <= r; j++) {

rst.push_back(matrix[u][j]); // 固定行u,列从l到r

}

u++; // 上边界下移:上面这一行已经全部遍历完

  • 遍历当前最上面一行的所有列

  • 遍历完后,这一行永远不会再被访问,所以u++

第二方向:从上到下(右边界)

for (int j = u; j <= d; j++) {

rst.push_back(matrix[j][r]); // 固定列r,行从u到d

}

r--; // 右边界左移:右边这一列已经全部遍历完

  • 遍历当前最右边一列的所有行(不包括已遍历的角点)

  • 注意起始是 j=u 而不是 j=u+1,因为 u 已经增加了

  • 遍历完后,这一列永远不会再被访问,所以r--

第三方向:从右到左(下边界)

if (u <= d) { // 重要:检查是否还有行需要遍历

for (int j = r; j >= l; j--) {

rst.push_back(matrix[d][j]); // 固定行d,列从r到l

}

d--; // 下边界上移:下面这一行已经全部遍历完

}

  • 为什么需要 if (u <= d) 判断?

    • 对于窄矩阵(列数>行数)的最后几轮,可能只剩下单行,可以通过判断进入while循环,但在从左到右遍历过之后已经遍历了整个矩阵,从上到下不会有影响,但如果再次从右到左遍历,就会重复添加同一行元素。

    • 例如:3×1的矩阵,只有一列,不需要从右到左遍历

第四方向:从下到上(左边界)

if (l <= r) { // 重要:检查是否还有列需要遍历

for (int j = d; j >= u; j--) {

rst.push_back(matrix[j][l]); // 固定列l,行从d到u

}

l++; // 左边界右移:左边这一列已经全部遍历完

}

五、语法要点

1.二维数组大小

vector<vector<int>> matrix; // 二维向量,可以看作矩阵

内存结构理解:

matrix = [

1, 2, 3\], // matrix\[0\] 是一个 vector\ \[4, 5, 6\], // matrix\[1\] 是一个 vector\ \[7, 8, 9\] // matrix\[2\] 是一个 vector\

访问元素的方式:

matrix[i][j] // 访问第i行第j列的元素

matrix[i] // 获取第i行的整个向量([1,2,3])

获取行列数:

// 获取行数(二维数组外层大小=行数)

int rows = matrix.size();

// 获取列数(二维数组取第一内层大小=列数)

int cols = matrix[0].size(); // 返回3

// 安全获取列数(先检查是否为空)

int cols = 0;

if (!matrix.empty()) {

cols = matrix[0].size();

}

六、执行示例

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]

执行过程:

  1. 初始化:l=0, r=2, u=0, d=2

  2. 第一轮循环

    • 上边界:1,2,3 → u=1

    • 右边界:6,9 → r=1

    • 下边界:8,7 (u=1 ≤ d=2) → d=1

    • 左边界:4 (l=0 ≤ r=1) → l=1

  3. 第二轮循环

    • 上边界:5 (l=1 ≤ r=1) → u=2

    • 右边界:(u=2 > d=1) 不执行

    • 下边界:(u=2 ≤ d=1) 不成立,不执行

    • 左边界:(l=1 ≤ r=1) 但 u=2 > d=1,不执行

  4. 循环结束

输出结果[1,2,3,6,9,8,7,4,5]

七、总结

本文介绍了螺旋矩阵的顺时针遍历算法。通过定义四个边界并使用边界收缩法,我们可以按照螺旋顺序遍历矩阵中的所有元素。算法的关键在于理解二维向量的结构:matrix.size()获取行数,matrix[0].size()获取列数(假设矩阵非空)。这种边界收缩法不仅思路清晰,而且代码简洁高效,时间复杂度为O(m×n),空间复杂度为O(1)(不考虑输出结果的空间)。

相关推荐
shx66661 小时前
2.1.2 ROS2 C++ 示例
c++·ros2
ベadvance courageouslyミ1 小时前
数据结构(一)
数据结构
什么时候才能变强1 小时前
k6面试高频问题
面试·职场和发展·k6
papership1 小时前
【入门级-算法-5、数值处理算法:高精度整数除以单精度整数的商和余数】
算法
lightqjx1 小时前
【C++】对set和map的使用
开发语言·数据结构·c++·stl
莫道桑榆晚丶1 小时前
Linux系统编程--------MP3项目实战
linux·学习
快乐zbc1 小时前
C++ 中 typedef 指针别名与 const 的坑
开发语言·c++
yoyo君~1 小时前
本地仓库推送到github
学习·github·无人机
crary,记忆1 小时前
React 之 useEffect
前端·javascript·学习·react.js