Leetcode1139 最大以1为边界的正方形(预处理数组技巧)

方法1:左神的暴力法和预处里数组检查法

class Solution {
    //数组预处理法,大幅度加快速度
    public int largest1BorderedSquare(int[][] grid) {
        if(grid.length==0||grid[0].length==0){
            return 0;
        }
        int[][] right=new int[grid.length][grid[0].length];
        int[][] down=new int[grid.length][grid[0].length];
        initPA(right,down,grid);
        int chang=grid[0].length;
        int height=grid.length;
        for(int k=Math.min(grid.length,grid[0].length);k>0;k--){//从最大边开始找,找到就返回k*k
            for(int i=0;i+k-1<height;i++){
                for(int j=0;j+k-1<chang;j++){
                    //检查边界是否都是1;
                    if(check(i,j,k,right,down)){
                        return k*k;
                    }
                }
            }
        }
        return 0;
    }
    public boolean check(int i,int j,int k,int[][] right,int[][] down){
        if(right[i][j]>=k&&down[i][j]>=k&&right[i+k-1][j]>=k&&down[i][j+k-1]>=k){
            return true;
        }
        return false;
    }
    public void initPA(int[][] right,int[][] down,int[][] grid){ //init prepare array
        //初始化right数组,从第一行最后边开始初始化
        for(int i=0;i<right.length;i++){
            for(int j=right[0].length-1;j>=0;j--){
                if(j==right[0].length-1&&grid[i][j]==1){
                    right[i][j]=1;
                }else if(j!=right[0].length-1&&grid[i][j]==1){
                    right[i][j]=right[i][j+1]+1;
                }
            }
        }
        //初始化down数组
        for(int j=0;j<down[0].length;j++){
            for(int i=down.length-1;i>=0;i--){
                if(i==down.length-1&&grid[i][j]==1){
                    down[i][j]=1;
                }else if(i!=down.length-1&&grid[i][j]==1){
                    down[i][j]=down[i+1][j]+1;
                }
            }
        }
    }
    
    
    
    
    //暴力检查法
    /**
    *有个注意的地方,就是边长,如只有1.这也是正方形,表示边长为1的正方形,所以for里面是i+k-1,因为这样才是边长
    */
    
    public int largest1BorderedSquare1(int[][] grid) {
        if(grid.length==0||grid[0].length==0){
            return 0;
        }
        int chang=grid[0].length;
        int height=grid.length;
        for(int k=Math.min(grid.length,grid[0].length);k>0;k--){//从最大边开始找,找到就返回k*k
            for(int i=0;i+k-1<height;i++){
                for(int j=0;j+k-1<chang;j++){
                    //检查边界是否都是1;
                    if(check1(i,j,k,grid)){
                        return k*k;
                    }
                }
            }
        }
        return 0;
    }
    public boolean check1(int i,int j,int k,int[][] grid){
        //一共检查四条边,第一条是第一横边,第二横边,第1戍边,第二戍边
        //但是可以发现,两个横边可以放在一起检查,两个戍边也可以放在一起检查,所以只需要两个for循环
        
        //首先检查横边
        for(int m=j;m<=j+k-1;m++){
            if(grid[i][m]!=1||grid[i+k-1][m]!=1){
                return false;
            }
        }
        //检查戍边
        for(int m=i;m<=i+k-1;m++){
            if(grid[m][j]!=1||grid[m][j+k-1]!=1){
                return false;
            }
        }
        return true;
    }
}

还有,例如求一个数组0-i位置的最大值,你可以这样:就是新建一个数组,然后遍历原数组,从头遍历,如果当前数小于前一个,就记录前一个,这样:
1 2 0 2 3 0 5-》
1 2 2 2 3 3 5 就这个意思,我的表达能力有问题。。。表达不清楚

方法2:leetcode大神方法,我搞不懂,暴力法是29秒,优化之后是13秒,但是这个和优化的时间复杂度只差在常数项,但是他是5秒,这个快的很多
没有去操作呢,回头看

class Solution {
    public int largest1BorderedSquare(int[][] grid) {
        if (grid.length==0) return 0;
        int[][] dpr = new int[grid.length+1][grid[0].length+1];
        int[][] dpc = new int[grid.length+1][grid[0].length+1];
        int dist, max=0;
        for (int r=1;r<=grid.length;r++){
            for (int c=1;c<=grid[0].length;c++){
                if (grid[r-1][c-1]==0) continue;
                dpr[r][c] = dpr[r-1][c]+1;
                dpc[r][c] = dpc[r][c-1]+1;
                dist = Math.min(dpr[r][c],dpc[r][c]);
                for (int i=dist;i>=1;i--){
                    **if (dpr[r][c-i+1]>=i** 
                        && dpc[r-i+1][c]>=i){
                        max = Math.max(max, i*i);
                        break;
                    }
                }
            }
        }
        return max;
    }
}

补丁:用的是leetcode大神思想做的,除了数组基准不同,其他的都一样,因为习惯我喜欢用原数组作为基准,他的思想就是从头到尾遍历数组,每一个点当做的是右下角的顶点,他有个处理非常好,就是left和up数组比grid数组要大一些,这样就不用初始化两条边了,代码简洁了,牛逼

class Solution {
    public int largest1BorderedSquare(int[][] grid) {
        if(grid.length==0||grid[0].length==0){
            return 0;
        }
        //他找的是右下角的点,以前我的做法是左上角,不一样的
        int[][] left=new int[grid.length+1][grid[0].length+1];
        int[][] up=new int[grid.length+1][grid[0].length+1];
        int max=0;
        //这个比grid大了一些,但是就是这些,使得后续的处理方便了,因为他相当于初始化了第一行和第一列,否则,还要
        //分支处理,加判断
        //leetcode大神,是用的left和up当基准的(更方便但是理解性差一点,所以我才用的是grid当做标准的)
        for(int i=0;i<grid.length;i++){
            for(int j=0;j<grid[0].length;j++){
                //每次到一个位置,先更新left和up数组
                if(grid[i][j]==0){
                    continue;//当前为0的不做任何判断,也不作任何处理
                }
                left[i+1][j+1]=left[i+1][j]+1;
                up[i+1][j+1]=up[i][j+1]+1;
                int k=Math.min(left[i+1][j+1],up[i+1][j+1]);//以当前为右下角顶点最大边长。主要是减少比较次数的,要不然你岂不是遍历很多次
                for(int dist=k;dist>0;dist--){
                    if(up[i+1][j+1-dist+1]>=dist&&left[i+1-dist+1][j+1]>=dist){
                        max=Math.max(max,dist);
                        break;
                    }
                }
            }
        }
        return max*max;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值