新手算法学习之路----二分法SmallestRectangle

题目:一个二维数组里面是由1和0构成的,里面所有的1都是相互关联的,有且只有一块由连续1构成的区域,请找出来最小能包括所有1的矩形,

前提:给出一个任意二维数组以及其中的一个1的元素的x和y坐标。

                             0,1,1,0

例如:int [2][3]a={{0,0,1,0},     1   这一行含有1,映射到行边上为1

                            {0,1,1,0},      1   同上

                            {0,1,0,0}}      1   同上

解题思想:如上面的例子里面,如果一列里面有1就映射到第一行对应的位置   如上面二维数组将所有含有1的列映射到第一行就形成了蓝色字体的0110,那么矩形的宽就出来,同理到长;

                 由给定的点来将长宽分为四部分来求,二维数组中红1为给定的点,那么就可以将长宽分为点左,右,上,下边的四部分。如:先求点左边第一个 1的位置,将问题转化为蓝色部分的数组,利用二分法来求,low = 0,high = y =1;下面代码中第一个while语句。

解题中遇到的问题:1,我TMD连java二维数组申明都不会用了。

                                2,while里面是low<=high 还是low<high&&(low+1)!=high,

                                3,left right up down四个变量最后该赋予那个值是 low还是high

解决的办法:如果用low<high&&(low+1)!=high,就必须在每个while语句后判断最终的low 与high哪一个为1,然后赋值给left这样会增加空间复杂度。

                     如果是low<=high 则直接可以将left = low;

public class SmallestRectangle {

           public static void main(String[] args) {
             char[][]array = {{'0','1','1','0'},
                              {'0','1','1','0'},
                              {'0','1','1','0'},
                              {'0','1','1','0'}};
             int x = minArea(array,0,1);
             System.out.println(x);
            }    
 
            static int minArea(char[][] image, int x, int y) { 
            int left,right,up,down;     //这四个变量分别表示点的左,右部分第一个含有‘1’的列的列号,以及上,下第一个含有‘1’的行的行号
            int low,high;               //这两个变量分别表示在while里面用来寻找中点的两端
            low = 0;
            high = y;
            int mid;
            
            //第一部分 while的功能是点的左边部分
            while(low<=high){                     //此while用来找点(x,y)右边的哥一个里面没有‘1’的列号
                boolean found = false;
                mid = low + (high- low)/2;
                for(int i =0;i<image.length;i++){  //image.length是二维数组的行号,用来对比一整列里面是否含有‘1’
                    if(image[i][mid]=='1'){
                        found = true;
                        break;
                    }
                }
                if(found)
                    high = mid-1;                  
                else
                    low = mid+1;                    
            }
            left= low;   //
            
            //第二部分while功能是点的右部分。
            low = y;
            high = image[x].length-1;                // image[x].length 为二维数组列的长度。
            while(low<high){
                boolean found_right = false;
                mid = low+(high-low)/2;
                for(int i = 0;i<image.length;i++){
                    if(image[i][mid]=='1'){
                        found_right = true;
                        break;
                    }
                }
                if(found_right) low = mid+1;
                else high = mid-1;
            }
            right = low;
            
            //第三个while的作用是找到点0到x所有的含有‘1’的行的行号
            low = 0;
            high = x;
            
            while(low<=high){
                boolean found_up = false;
                mid = low+ (high-low)/2;
                for(int i =0;i<image[x].length;i++){
                    if(image[mid][i]=='1'){
                        found_up = true;
                        break;
                    }
                }
                if(found_up)  high = mid-1;
                else low = mid+1;                
            }
            up = low;            
            
            //第四个while的作用是找到点0到x所有的含有‘1’的行的行号
            low = x;
            high = image.length-1;            
            while(low<=high){
                boolean found_down = false;
                mid = low+ (high-low)/2;
                for(int i =0;i<image[x].length;i++){
                    if(image[mid][i]=='1'){
                        found_down = true;
                        break;
                    }
                }
                if(found_down)  low = mid+1;
                else high = mid-1;                
            }
            down = low;
            return (right-left)*(down-up);         
            
            
        
    }

 

使用模板后改的代码同样可运行:

模板为:start+1<end;

              mid=start+(end-start)/2;

              A[mid] <>==target;

              A[start],A[end]?target;

int minArea(char[][] image, int x, int y) { 
            int left,right,up,down;     //这四个变量分别表示点的左,右部分第一个含有‘1’的列的列号,以及上,下第一个含有‘1’的行的行号
            int low,high;               //这两个变量分别表示在while里面用来寻找中点的两端
            low = 0;
            high = y;
            int mid;
            
            //第一部分 while的功能是点的左边部分
            while(low+1<high){                     //此while用来找点(x,y)右边的哥一个里面没有‘1’的列号
                boolean found = false;
                mid = low + (high- low)/2;
                for(int i =0;i<image.length;i++){  //image.length是二维数组的行号,用来对比一整列里面是否含有‘1’
                    if(image[i][mid]=='1'){
                        found = true;
                        break;
                    }
                }
                if(found)
                    high = mid;                  
                else
                    low = mid;                    
            }
            boolean f1 = false;
            for(int i =0;i<image.length;i++){  //image.length是二维数组的行号,用来对比一整列里面是否含有‘1’
                if(image[i][high]=='1'){
                    f1 = true;
                    break;
                }
            }
            if(f1) left = high;
            else left = low;
            //left= low;   //
            
            //第二部分while功能是点的右部分。
            low = y;
            high = image[x].length-1;                // image[x].length 为二维数组列的长度。
            while(low+1<high){
                boolean found_right = false;
                mid = low+(high-low)/2;
                for(int i = 0;i<image.length;i++){
                    if(image[i][mid]=='1'){
                        found_right = true;
                        break;
                    }
                }
                if(found_right) low = mid;
                else high = mid;
            }
            boolean f2 = false;
            for(int i = 0;i<image.length;i++){
                if(image[i][high]=='1'){
                    f2 = true;
                    break;
                }
            }
            if(f2)right = high;
            else  right = low;
            
            //第三个while的作用是找到点0到x所有的含有‘1’的行的行号
            low = 0;
            high = x;
            
            while(low+1<high){
                boolean found_up = false;
                mid = low+ (high-low)/2;
                for(int i =0;i<image[x].length;i++){
                    if(image[mid][i]=='1'){
                        found_up = true;
                        break;
                    }
                }
                if(found_up)  high = mid;
                else low = mid;                
            }
            boolean f3 = false;
            for(int i =0;i<image[x].length;i++){
                if(image[high][i]=='1'){
                    f3 = true;
                    break;
                }
            }
            if(f3) up=high;
            else up = low;
            //up = low;            
            
            //第四个while的作用是找到点0到x所有的含有‘1’的行的行号
            low = x;
            high = image.length-1;            
            while(low+1<high){
                boolean found_down = false;
                mid = low+ (high-low)/2;
                for(int i =0;i<image[x].length;i++){
                    if(image[mid][i]=='1'){
                        found_down = true;
                        break;
                    }
                }
                if(found_down)  low = mid+1;
                else high = mid-1;                
            }
            boolean f4 = false;
            for(int i =0;i<image[x].length;i++){
                if(image[high][i]=='1'){
                    f4 = true;
                    break;
                }
            }
            if(f4) down = high;
            else  down = low;
            
            return (right-left+1)*(down-up+1);   
    }

 

转载于:https://www.cnblogs.com/junliu37/p/7136245.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值