文章目录
二维矩阵针对不同问题的遍历思路(算法)
右上角开始遍历
情景
在一个 n * m 的二维数组中,
每一行都按照从左到右递增的顺序排序,
每一列都按照从上到下递增的顺序排序。
判断此数组中是否含有该整数。
矩阵情况如下图所示
分析
以右上角为出发点值为begin,对于寻找的数字target,有以下三种情况
- 如果target大于begin,就排除了左边的行,begin=array[i+1][j]
- 如果target小于begin,就排除了下边的列 begin=array[i][j-1]
- 如果等于就找到啦
Code
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if(matrix.length==0)return false;
int i=0;
int j=matrix[0].length-1;
while (i<matrix.length&&j>=0){
if(matrix[i][j]>target){
j--;
}else if(matrix[i][j]<target){
i++;
}else {
return true;
}
}
return false;
}
左上角和右下角配合遍历
情景
左上角和右下角两个起点开始遍历,能够从四个方向分别接触矩阵的每个点,在某些情况下有奇效
在一个大小在 (0, 0) 到 (N-1, N-1) 的2D网格 grid 中,除了在 mines 中给出的单元为 0,其他每个单元都是 1。网格中包含 1 的最大的轴对齐加号标志是多少阶?返回加号标志的阶数。如果未找到加号标志,则返回 0。
一个 k" 阶由 1 组成的“轴对称”加号标志具有中心网格 grid[x][y] = 1 ,以及4个从中心向上、向下、向左、向右延伸,长度为 k-1,由 1 组成的臂。下面给出 k" 阶“轴对称”加号标志的示例。注意,只有加号标志的所有网格要求为 1,别的网格可能为 0 也可能为 1。
简而言之
在一个二维矩阵中,有0也有1,
k 阶轴对称加号标志示例:
阶 1:
000
010
000
阶 2:
00000
00100
01110
00100
00000
阶 3:
0000000
0001000
0001000
0111110
0001000
0001000
0000000
示例 1
输入: N = 5, mines = [[4, 2]]
输出: 2
解释:
11111
11111
11111
11111
11011
示例 2:
输入: N = 2, mines = []
输出: 1
解释:
11
11
没有 2 阶加号标志,有 1 阶加号标志。
分析 思路一 暴力遍历加简单优化
思路:对每一点,沿上下左右四个方向伸展,如果四个方向有一个位置为0就伸展失败
优化:随着我们查找十字架的增多,边缘位置就不需要查找了,能够节省一定时间
暴力code
int[][] array;
public int orderOfLargestPlusSign(int n, int[][] mines) {
array=new int[n][n];
for (int i = 0; i < mines.length; i++) {
array[mines[i][0]][mines[i][1]]=-1;
}
if(n*n==mines.length)return 0;
int max=1;
for (int i = max; i < n-max; i++) {
for (int j = max; j < n-max; j++) {
if(array[i][j]==0)max=Math.max(max,judge(i,j,1,n));
}
}
return max;
}
public int judge(int i,int j,int num,int n){
//System.out.println(num);
if(i-num<0||i+num>=n||j-num<0||j+num>=n){
return num;
}
if(array[i-num][j]==-1||array[i+num][j]==-1||array[i][j-num]==-1||array[i][j+num]==-1){
return num;
}
return judge(i,j,num+1,n);
}
分析 思路二 加上动态规划的实现
- 从左上角开始遍历,计算每个点向左和向上的臂长
例如某点的左臂最长值,dp[i][j][左]=dp[i][j-1][左臂值]+dp[i][j][值];
- 从右下角开始遍历,计算每个点向右和向下的臂长
计算过程也是同上 - 得到四个臂长后,最大的十字架就是四个臂长的最小值了
code
public int orderOfLargestPlusSign(int n, int[][] mines) {
int max=0;
if(n*n==mines.length)return 0;
int[][][]array=new int[n][n][4];
for (int i = 0; i < mines.length; i++) {
array[mines[i][0]][mines[i][1]][0]=-1;
array[mines[i][0]][mines[i][1]][1]=-1;
array[mines[i][0]][mines[i][1]][2]=-1;
array[mines[i][0]][mines[i][1]][3]=-1;
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if(array[i][j][0]==0){
if(i!=0){
array[i][j][0]=Math.max(0,array[i-1][j][0])+ 1;
}else{
array[i][j][0]= 1;
}
if(j!=0){
array[i][j][1]=Math.max(0,array[i][j-1][1])+ 1;
}else{
array[i][j][1]=1;
}
}
}
}
for (int i = n-1; i >=0 ; i--) {
for (int j = n-1; j >=0 ; j--) {
if(array[i][j][3]==0){
if(i!=n-1){
array[i][j][2]=Math.max(0,array[i+1][j][2])+ 1;
}else{
array[i][j][2]=1;
}
if(j!=n-1){
array[i][j][3]=Math.max(0,array[i][j+1][3])+ 1;
}else{
array[i][j][3]=1;
}
max=Math.max(max,getMin(array[i][j]));
}
}
}
return max;
}
public Integer getMin(int[] array){
int min=Integer.MAX_VALUE;
for (int i = 0; i < array.length; i++) {
min=Math.min(array[i],min);
}
return min;
}