前言
刷力扣hot100,记录一下每题的思路~
这次是矩阵相关的题目
①两个boolean数组记录要置零的行列号,遍历数组置零对应的行列
java
复制代码
class Solution {
public void setZeroes(int[][] matrix) {
int m=matrix.length, n=matrix[0].length;
// 记录要置零的行列号
boolean[] row=new boolean[m], col=new boolean[n];
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(matrix[i][j]==0){
row[i]=true;
col[j]=true;
}
}
}
// 将对应行列置零
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(row[i]||col[j])matrix[i][j]=0;
}
}
}
}
②第一行第一列记录对应行列是否要置零。
0\]\[0\]同时代表行列,不能直接置零,使用两个boolean单独记录。
先遍历矩阵修改对应第一行第一列,置零除第一行第一列(标志位用于后续判断)的元素,再根据boolean处理第一行第一列
```java
class Solution {
public void setZeroes(int[][] matrix) {
int m=matrix.length, n=matrix[0].length;
// [0][0]同时代表行列,不能直接置零,单独处理
boolean row0=false, col0=false;
for(int j=0;j=0;i--){ // 第一行标志位最后处理
for(int j=1;j spiralOrder(int[][] matrix) {
List ans = new ArrayList<>();
int m=matrix.length, n=matrix[0].length; // 行列
int[][] dir={{0,1},{1,0},{0,-1},{-1,0}}; // 方向矩阵
int x=0, y=0, dirIdx=0; // 当前位置、方向下标
boolean[][] flag = new boolean[m][n]; // 是否已访问
for(int i=0;i=m || y1<0||y1>=n || flag[x1][y1])
dirIdx=(dirIdx+1)%4;
// 更新位置
x+=dir[dirIdx][0];
y+=dir[dirIdx][1];
}
return ans;
}
}
```
②**按层**模拟。
lrtb记录每层的上下左右,四个for循环遍历每边,前两个for循环之后修改了t和r,**后两个** for循环要**重新判断**是否满足t\<=b和l\<=r,判断上下或者左右是否已走完
```java
class Solution {
public List spiralOrder(int[][] matrix) {
List ans = new ArrayList<>();
int m=matrix.length, n=matrix[0].length; // 行列
int l=0, r=n-1, t=0, b=m-1; // 上下左右范围
while(l<=r&&t<=b){
for(int j=l; j<=r; j++)ans.add(matrix[t][j]); // 左到右
t++;
for(int i=t; i<=b; i++)ans.add(matrix[i][r]); // 上到下
r--;
if(t<=b) // 判断是否上下走完了
for(int j=r; j>=l; j--)ans.add(matrix[b][j]); // 右到左
b--;
if(l<=r) // 判断左右是否走完了
for(int i=b; i>=t; i--)ans.add(matrix[i][l]); // 下到上
l++;
}
return ans;
}
}
```
③同上,在**每个** for循环后判断**边界**是否合法,不合法就break,便于理解
```java
class Solution {
public List spiralOrder(int[][] matrix) {
List ans = new ArrayList<>();
int m=matrix.length, n=matrix[0].length; // 行列
int l=0, r=n-1, t=0, b=m-1; // 上下左右范围
while(l<=r&&t<=b){
for(int j=l; j<=r; j++)ans.add(matrix[t][j]); // 左到右
if(++t>b) break;
for(int i=t; i<=b; i++)ans.add(matrix[i][r]); // 上到下
if(--r=l; j--)ans.add(matrix[b][j]); // 右到左
if(--b=t; i--)ans.add(matrix[i][l]); // 下到上
if(++l>r) break;
}
return ans;
}
}
```
## (3)[48. 旋转图像](https://leetcode.cn/problems/rotate-image/description/?envType=study-plan-v2&envId=top-100-liked "48. 旋转图像")
①暴力。每次旋转包含四个数,从左上角开始遍历四分之一的位置,**逆时针** 替换,计算**每个替换值的位置**,只需要记录一个变量
```java
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
// 左上角
for(int i=0;ib||l>r)return false; // 区域不存在
if(t==b&&l==r)return matrix[t][l]==target; // 一个元素
// 对角线
int i=t,j=l;
for(;i<=b&&j<=r;i++,j++) if(matrix[i][j]>=target)break;
if(i<=b&&j<=r&&matrix[i][j]==target)return true; // 在对角线上
// 左下和右上
return check(matrix,i,b,l,j-1,target)||check(matrix,t,i-1,j,r,target);
}
}
```
③**二分查找**,对每行进行二分查找
④**右上角** ,为一行最大和一列最小。若**大于** target,该列都大于target,y--;若**小于** target,该行都小于target,x++。直到找到。(类似从**左下角**开始也可以,条件反过来)
```java
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m=matrix.length, n=matrix[0].length;
int x=0,y=n-1; // 右上角开始
while(x=0){
if(matrix[x][y]==target)return true; // 找到
if(matrix[x][y]>target)y--; // y这列都大于target
else x++; // x这行都小于target
}
return false;
}
}
```
## 总结
①**矩阵置零** 。使用**第一行第一列**来标记每行每列,注意特别判断\[0\]\[0\]位置
②**螺旋矩阵** 。用**方向数组和下标** 模拟旋转;**按层**遍历,用lrtp记录上下左右要遍历的层,要注意判断边界是否合法
③**旋转矩阵** 。总结**旋转规律** ,i,j旋转到j,n-i-1,逆时针替换只需要记录一个变量;先**转置** 为j,i,再**左右翻转**为j,n-i-1
④**搜索二维矩阵Ⅱ** 。**暴力** 遍历;**递归** ,从对角线开始判断,划分四个区域,递归左下和右上;对每行用**二分查找** ;利用**右上** 或者**左下**的特殊性,每次收缩一行或一列。