力扣刷题攻略数组篇-特定顺序遍历二维数组

本文介绍了如何解决LeetCode中的54螺旋矩阵、59螺旋矩阵II和498对角线遍历问题,提供了详细的题目描述、分析和C++代码解答,展示了矩阵遍历的不同策略和技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


文章内容是自己刷leetcode官方刷题攻略的一些经验与总结。
题目链接详见 leetcode刷题攻略
如果喜欢的话,别忘了点个赞哦 ^ _ ^

一.54螺旋矩阵

1.题目描述

在这里插入图片描述
在这里插入图片描述

2.题目分析与解答

对于这道题,我们可以使用 “做减法” 的思想。那么什么是 “做减法” 呢?

我们发现可以将遍历顺序看成这样四个过程,上面一层,右边一层,下面一层,左边一层。完成一个循环,也就是一圈。

可以记录一下矩阵的四个边界,遍历完一层后更新边界,如果边界冲突,比如下边界大于上边界,那就一定遍历完了,结束循环。在遍历过程中,更新答案。

C++ 代码如下:

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        //可以使用定义上下左右边界的方法
        //当遍历完一行或一列,更新边界,判断是否满足结束条件
        //比如遍历完一行,更新上边界,上边界大于下边界就结束循环
        
        
        vector<int> ans;
        int u = 0, l = 0; //上边界和左边界
        int b = matrix.size() - 1, r = matrix[0].size() - 1; //下边界和右边界
        while(true) {
            for(int i = l; i <= r; i ++) { //右
                ans.push_back(matrix[u][i]);
            }
            if(++ u > b) break; //更新上边界

            for(int i = u; i <= b; i ++) { //下
                ans.push_back(matrix[i][r]);
            }
            if(-- r < l) break; //更新右边界

            for(int i = r; i >= l; i --) { //左
                ans.push_back(matrix[b][i]);
            }
            if(-- b < u) break; //更新下边界

            for(int i = b; i >= u; i --) { //上
                ans.push_back(matrix[i][l]);
            }
            if(++ l > r) break; //更新左边界
        }

        return ans;
    }
};

二.59螺旋矩阵II

1.题目描述

在这里插入图片描述

在这里插入图片描述

2.题目分析与解答

这个题目与上一个题目类似,不过这个题目是给你一个 n,你需要生成这个螺旋矩阵。

那矩阵的生成顺序还是上右下左为一个循环,我们可以设置一个循环的初始点,从坐标(0,0)开始,每一次循环结束,遍历的初始点横纵坐标都加一,我们可以用 startx = 0,starty = 0 来表示初始点

每一圈的循环后,终止边界都会减一,用一个变量 offset = 0 来控制。每一圈结束后加一。

还有一个问题,我们需要转几圈呢?这个根据 n 来确定,循环的圈数为 n / 2 向下取整,如果 n 是偶数,那正好转完,如果 n 为奇数,我们还需要特殊处理中心位置,将其单独赋值即可。

C++ 代码如下:

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        //我们可以发现根据n生成的方阵,每一圈都是右下左上的一个顺序
        //所以可以一层一层赋值
        //那么需要设定一个每一层的开始值,startx表示开始的行,starty表示开始的列
        //每次循环完一层,startx与starty都加一
        //那么一共循环几层呢
        //如果n是偶数,会循环n/2层
        //如果n是奇数,会循环n/2 + 1层,这里n/2是向下取整的结果

        vector<vector<int>> ans(n, vector<int>(n, 0));
        int cnt = 1;
        int startx = 0, starty = 0;
        int loop = n / 2;
        int offset = 1; //用来控制边界
        while(loop --) {
            int i = startx, j = starty;
            for(; j < n - offset; j ++) ans[i][j] = cnt ++;
            for(; i < n - offset; i ++) ans[i][j] = cnt ++;
            for(; j > starty; j --) ans[i][j] = cnt ++;
            for(; i > startx; i --) ans[i][j] = cnt ++;

            startx ++;
            starty ++;
            offset ++;
        }

        if(n % 2 == 1) ans[n / 2][n / 2] = cnt; //特殊处理n为奇数的最中间数字

        return ans;

    }
};

三.498对角线遍历

1.题目描述

在这里插入图片描述
在这里插入图片描述

2.题目分析与解答

从整体来看,我们发现对角线遍历其实只有两个方向,左下到右上,右上到左下,而且这两个方向也是有规律的。如果我们对角线从 0 开始记,那么偶数对角线顺序是左下到右上,奇数对角线顺序是右上到左下

然后分析具体细节,就拿左下到右上这个方向来说。
我们发现遍历的初始点其实与当前对角线的下标 i 和矩阵的行数 m 有关。
如果 i < m,那么初始点为(i,0),否则为(m - 1,i - m + 1)。

从右上到左下这个方向也类似,对比的就是对角线的下标 i 与矩阵的列数 n 。
如果 i < n,那么初始点为(0,i),否则为(i - n + 1,n -1)。

C++ 代码如下:

class Solution {
public:
    vector<int> findDiagonalOrder(vector<vector<int>>& mat) {
        //对角线遍历有两种方向:左下到右上,右上到左下
        //我们可以统计对角线的个数,来当作遍历次数
        //在遍历时会根据对角线的奇偶进行调整遍历的初始点

        int m = mat.size();
        int n = mat[0].size();
        vector<int> ans;
        int cnt = m + n - 1; //对角线的个数
        //偶数对角线左下到右上,奇数对角线右上到左下
        for(int i = 0; i < cnt; i ++) {
            if(i % 2 == 0) {
                int x = i >= m ? m - 1 : i;
                int y = i >= m ? i - m + 1 : 0;
                while(x >= 0 && y < n) {
                    ans.push_back(mat[x][y]);
                    x --;
                    y ++;
                }
            } else {
                int x = i >= n ? i - n + 1 : 0;
                int y = i >= n ? n - 1 : i;
                while(x < m && y >= 0) {
                    ans.push_back(mat[x][y]);
                    x ++;
                    y --;
                }
            }
        }

        return ans;
        

    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Echo夏末

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值