二维矩阵针对不同问题的遍历思路(算法)

二维矩阵针对不同问题的遍历思路(算法)

右上角开始遍历

情景

在一个 n * m 的二维数组中,
每一行都按照从左到右递增的顺序排序,
每一列都按照从上到下递增的顺序排序。
判断此数组中是否含有该整数。
矩阵情况如下图所示

image.png

分析

以右上角为出发点值为begin,对于寻找的数字target,有以下三种情况

  1. 如果target大于begin,就排除了左边的行,begin=array[i+1][j]
  2. 如果target小于begin,就排除了下边的列 begin=array[i][j-1]
  3. 如果等于就找到啦

image.png

image.png

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,

image.png

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);

    }

分析 思路二 加上动态规划的实现

  1. 从左上角开始遍历,计算每个点向左和向上的臂长
    例如某点的左臂最长值,dp[i][j][左]=dp[i][j-1][左臂值]+dp[i][j][值];

image.png

  1. 从右下角开始遍历,计算每个点向右和向下的臂长
    计算过程也是同上
  2. 得到四个臂长后,最大的十字架就是四个臂长的最小值了

image.png

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;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值