例一:对角线遍历
链接:https://leetcode-cn.com/problems/diagonal-traverse/
题目描述:给你一个大小为 m x n 的矩阵 mat ,请以对角线遍历的顺序,用一个数组返回这个矩阵中的所有元素。
示例 1:
输入:mat = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,4,7,5,3,6,8,9]
示例 2:
输入:mat = [[1,2],[3,4]]
输出:[1,2,3,4]
提示:
m == mat.length
n == mat[i].length
1 <= m, n <= 104
1 <= m * n <= 104
-105 <= mat[i][j] <= 105
题目分析:
刚看到这个题目的时候,我心里飘过的想法是就普普通通的遍历嘛,但是在真正准备写代码的时候发现并没有这么简单。
经过分析可以发现数学规律:
1、上图中红色线的对角线上的坐标之和均为偶数且在遍历时是向上移动。
2、黄色线对角线上的坐标之和均为奇数,且均为向下移动。
3、对角线上遍历时(不考虑边界)上移是(x+1,y-1),下移是(x-1,y+1)。
在弄清楚上面几条过后,这个题的思路就已经清晰了,但是我们还需要考虑边界问题,即上图中的1,4,3,8等位置。
而边界主要是第一列,最后一列和第一行,最后一行
具体边界边界判断及处理如下:
if((x+y)%2==0){//对角线坐标之和为偶数,向上移动
if(y==col-1)x++;//最后一列
else if(x==0)y++;//第一行
else x--,y++;//否则就正常的斜向上移动
}
else{//对角线之和为奇数,向下移动
if(x==row-1)y++;//最后一行
else if(y==0)x++;//第一列
else x++,y--;
}
class Solution {
public:
vector<int> findDiagonalOrder(vector<vector<int>>& mat) {
vector<int>result;
int row=mat.size(),col=mat[0].size();
if(row==0||col==0){
return {};
}
int sum=row*col;
int x=0,y=0;
for(int i=0;i<sum;++i){
result.push_back(mat[x][y]);
if((x+y)%2==0){//对角线坐标之和为偶数,向上移动
if(y==col-1)x++;//最后一列
else if(x==0)y++;//第一行
else x--,y++;//否则就正常的斜向上移动
}
else{//对角线之和为奇数,向下移动
if(x==row-1)y++;//
else if(y==0)x++;
else x++,y--;
}
}
return result;
}
};
例二:螺旋矩阵
链接:https://leetcode-cn.com/problems/spiral-matrix/
题目描述:
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 10
-100 <= matrix[i][j] <= 100
题目分析:
这也是一个矩阵遍历的问题,和上题相似,只要将边界条件和走一圈步数会递减的点抓住就好了。
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int>result;
int l=0,m=matrix.size()-1,u=0,n=matrix[0].size()-1;
while(l<=m&&u<=n){
for(int i=l;i<=n;i++)//向右
result.push_back(matrix[u][i]);
for(int i=u+1;i<=m;i++)//向下
result.push_back(matrix[i][n]);
for(int i=n-1;i>=l&&u<m;i--)//向左
result.push_back(matrix[m][i]);
for(int i=m-1;i>u&&l<n;i--)
result.push_back(matrix[i][l]);//向上
l++,n--,u++,m--;//n--,m--类似于“缩圈”
}
return result;
}
};
例三:岛屿的周长(简单)
链接:https://leetcode-cn.com/problems/island-perimeter/
题目描述:
给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域。
网格中的格子 水平和垂直 方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。
岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。
输入:grid = [[0,1,0,0],[1,1,1,0],[0,1,0,0],[1,1,0,0]]
输出:16
示例 2:
输入:grid = [[1]]
输出:4
示例 3:
输入:grid = [[1,0]]
输出:4
提示:
row == grid.length
col == grid[i].length
1 <= row, col <= 100
grid[i][j] 为 0 或 1
拿到这个题时,最容易想到的就是两种优先搜索,这确实是一种方法,但是就这个题而言,可能用优先搜索会有一些小题大做了。
我的思路是对这个矩阵遍历,在遇到与岛屿(grid[i][j]==1)的边界相连的不是岛屿时,周长加1。即只有在周围为水或者矩阵边界时,这一个小正方形的边才算作岛屿的周长。
lass Solution {
public:
int direction[4][2]={0,1,1,0,-1,0,0,-1};
int islandPerimeter(vector<vector<int>>& grid) {
int result=0;
for(int i=0;i<grid.size();i++){
for(int j=0;j<grid[0].size();j++){
if(grid[i][j]==1){
for(int k=0;k<4;k++){
int x=i+direction[k][0];
int y=j+direction[k][1];
if(x<0||x>=grid.size()||y<0||y>=grid[0].size()||grid[x][y]==0){
result++;
}
}
}
}
}
return result;
}
};
代码中的direction表示四个方向。写成矩阵即:
0,1
1,0
-1,0
0,-1