文章内容是自己刷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;
}
};