zoukankan      html  css  js  c++  java
  • 读书笔记之《程序员代码面试指南(数组和矩阵问题)》

    数组和矩阵问题,这些做得比较多。

    未排序正整数数组中累加和为给定值的最长子数组长度

    package Array;
    
    /**
     * Created by zdmein on 2017/8/30.
     *未排序正整数数组中累加和为给定值的最长子数组长度
     * 给定一个无需数组arr,其中元素为正,给定一个整数k。求arr的所有子数组中累加和为k的最长子数组的长度。
     * arr=[1,2,1,1,1],k=3
     * 结果返回3
     */
    public class getMaxLength1 {
        public static void main(String [] args){
            int [] arr={1,2,1,1,1};
            int k=3;
            System.out.println(getMaxLength(arr,k));
    
        }
    
        public static int getMaxLength(int [] arr ,int k){
            if(arr==null||arr.length<0||k<0){
                return 0;
            }
    
            int right =0;
            int left=0;
            int len=0;
            int sum=arr[0];
            while (right<arr.length){
                if(sum==k){
                    len=Math.max(len,right-left+1);
                    sum-=arr[left++];
                }else if(sum<k){
                    right++;
                    if(right==arr.length){
                        break;
                    }
                    sum+=arr[right];
                }else {
                    sum-=arr[left++];
                }
            }
            return len;
        }
    }
    

    数组partition调整使数组的左部分单调有序

    给定一个有序数组arr,调整使得数组的左部分无重复元素且有序,右边部分不要求。如数组arr[]={1,2,2,2,3,3,4,5,6,9,9} ;调整过后可以为:[1, 2, 3, 4, 5, 6, 9, 2, 3, 2, 9] 。

    思路:使用标记 u 其中arr[0…u] 表示已经处理过的没有重复元素且有序的区间,从arr[u+1…i-1]表示有重复元素的部分。则算法主要分为下面两部分。
    1. 比较 arr[i] 与 arr[u] 是否相同如果不同,则将 arr[i] 的值赋给arr[u+1],u++;
    2. i++遍历数组。

    import java.util.HashSet;
    public class Main {
        public static void main(String[] args) {
            int[] arr = {1, 2, 2, 2, 3, 3, 4, 5, 6, 6, 7, 7, 8, 8, 8, 9};
            leftUnique(arr);
        }
    
        public static void leftUnique(int[] arr) {
            if (arr.length == 0 || arr == null) {
                return;
            }
            int u=0;
            int i=1;
            while (i!=arr.length){
                if(arr[i++]!=arr[u]){
                   swap(arr,i-1,++u);
                }
            }
            for( i=0;i<arr.length;i++){
                System.out.print(arr[i]+" ");
            }
    
        }
        public static int []  swap(int[] arr,int m, int n){
            int temp= arr[m];
            arr[m]=arr[n];
            arr[n]=temp;
            return arr ;
        }
    }
    

    将正方形矩阵顺时针转动90度

    题目:给定一个N*N的矩阵matrix,求把这个矩阵调整成顺时针转动90度后的形式。

    例如:

    1 2 3 4

    5 6 7 8

    9 10 11 12

    13 14 15 16

    顺时针转动90度后为:

    13 9 5 1

    14 10 6 2

    15 11 7 3

    16 12 8 4

    要求:额外空间复杂度为O(1)

    public class Main {
        public static void main(String[] args) {
           int[][] m = { {1,2,3,4},
                         {5,6,7,8},
                         {9,10,11,12},
                         {13,14,15,16} };
            rotate(m);
        }
    
        public static void rotate(int[][] arr) {
           int tR=0;
           int tC=0;
           int dR=arr.length-1;
           int dC=arr[0].length-1;
           while (tR<dR){
               rotateEdge(arr,tR++,tC++,dR--,dC--);
           }
           for (int i=0;i<arr.length;i++) {
               for (int j = 0; j < arr[0].length; j++) {
                   System.out.print(arr[i][j] + "  ");
               }
               System.out.println(" ");
           }
        }
    
        public static void rotateEdge(int [][] arr ,int  tR,int tC ,int dR ,int dC){
            int times=dR-tR;
            int temp=0;
            for(int i=0;i!=times;i++){
                temp = arr[tR][tC+i];
                arr[tR][tC+i]=arr[dR-i][tC];
                arr[dR-i][tC]=arr[dR][dC-i];
                arr[dR][dC-i]=arr[tR+i][dC];
                arr[tR+i][dC]=temp;
            }
        }
    }
    

    找到无序数组中最小的K个数

    给定一个无序的整型数组arr,找到其中最小的k个数。

    时间复杂度:O(nlogk)

    维护一个有k个数的大根堆,这个堆代表目前选出的k个最小的数。在堆的k个元素中堆顶元素是最小的k个数中最大的那个。

    接下来要遍历整个数组,遍历的过程中看当前数是否比堆顶元素小。如果是,就把堆顶元素替换成当前数,然后调整堆。如果不是,则不做任何操作,继续遍历下一个数。在遍历完成后,堆中的k个数就是所有数组中最小的k个数。

    public class Main {
        public static void main(String[] args) {
           int[] arr = {5 ,9,3,4,7,2,8,1,6};
            int k=3;
           int [] res= getMinKNumsByHeap(arr,k);
           for(int i=0;i<res.length;i++){
               System.out.println(res[i]);
           }
        }
    
        public static int [] getMinKNumsByHeap(int[] arr,int k) {
            if(k<1&&k>arr.length){
                return arr;
            }
    
            int kHeap[]=new int [k];
            for(int i=0;i!=k;i++){
                heapInsert(kHeap,arr[i],i);
            }
            for(int i = k;i !=arr.length;i++){
                if(arr[i]<kHeap[0]){
                    kHeap[0]=arr[i];
                    heapify(kHeap,0,k);
                }
            }
           return kHeap;
    
            }
    
            public static void heapify(int [] arr, int index ,int heapsize){
            int left= index*2+1;
            int right=index*2+2;
            int largest=index;
            while(left<heapsize){
                if(arr[left]>arr[index]){
                    largest=left;
                }
                if(right<heapsize && arr[right]>arr[largest]){
                    largest=right;
                }
    
                if(largest!=index){
                    swap(arr,largest,index);
                }else {
                    break;
                }
                index=largest;
                left= index*2+1;
                right=index*2+2;
            }
        }
    
            public static void heapInsert(int [] kHeap ,int arri ,int i){
            kHeap[i]=arri;
            while (i!=0){
                int parent=(i-1)/2;
                if(kHeap[parent]<kHeap[i]){
                    swap(kHeap,parent,i);
                    i=parent;
                }else {
                    break;
                }
            }
        }
    
            public static void swap(int [] arr ,int m ,int n){
                int temp=arr[m];
                arr[m]=arr[n];
                arr[n]=temp;
            }
        }
    

    三数排序

    给定一个数组,其中只有三个数0,1,2三个值,请实现arr排序。

    三个颜色的球排序

    用left和right标记数组头和尾,用index遍历,遇到该交换的交换,直到index==right为止。

    import java.util.HashSet;
    public class Main {
        public static void main(String[] args) {
            int[] arr = {1,0,2,0,1,2,1,0 ,2, 2,0};
            leftUnique(arr);
        }
    
        public static void leftUnique(int[] arr) {
            if (arr.length <2 || arr == null) {
                return;
            }
            int left=-1;
            int index=0;
            int right=arr.length;
            while (index<right){
                if(arr[index]==0){
                    swap(arr,++left,index++);
                }else if(arr[index]==2){
                    swap(arr,--right,index);
                }else {
                    index++;
                }
            }
            for(int  i=0;i<arr.length;i++){
                System.out.print(arr[i]+" ");
            }
        }
      
        public static int []  swap(int[] arr,int m, int n){
            int temp= arr[m];
            arr[m]=arr[n];
            arr[n]=temp;
            return arr ;
        }
    }
    

    转圈打印矩阵

    给一个整型矩阵matrix,按照转圈的方式打印它。

    1 2 3

    4 5 6

    7 8 9

    打印就是:1 2 3 6 9 8 7 4 5

    public class CircleDynamic {
        public static void main(String [] args){
            int [][] m= {{1,2,3,4},
                    {5,6,7,8},
                    {9,10,11,12},
                    {13,14,15,16}};
    
            spirOrderPrint(m);
        }
    
      public static void spirOrderPrint(int [][]matrix){
            int tR = 0;
            int tC = 0;
            int dR=matrix.length-1;
            int dC=matrix[0].length-1;
            while (tR<=dR && tC<=dC){
                printEdge(matrix,tR++,tC++,dR--,dC--);
            }
        }
    
        public static void printEdge(int [][] matrix ,int tR ,int tC,int dR , int dC){
          if(tR==dR){
              for(int i=0;i<=dC;i++){
                  System.out.print(matrix[tR][i]+" ");
              }
    
          }else if(tC==dC){
              for(int i=0;i<dR ;i++){
                  System.out.print(matrix[i][tC]+ " ");
              }
          }else {
              int curC=tC;
              int curR=tR;
              while (curC != dC){
                  System.out.print(matrix[tR][curC]+" ");
                    curC++;
              }
              while (curR!=dR){
                  System.out.print(matrix[curR][dC]+" ");
                  curR++;
              }
    
              while (curC != tC){
                  System.out.print(matrix[dR][curC]+" ");
                  curC--;
              }
              while (curR!=tR){
                  System.out.print(matrix[curR][tC]+" ");
                  curR--;
              }
          }
        }
    }
    

    "之"字形打印矩阵

    1. 上坐标(tR,tC)初始为(0,0),先向右走(tC++),再向下走tR++
    2. 下坐标类似
    3. 打印斜线方向用boolean判断
    public class CircleDynamic {
        public static void main(String [] args){
            int [][] m= {{1,2,3,  4},
                         {5,6,  7,   8},
                         {9,  10,  11,  12},
                         {13,  14,    15,   16}};
    
            printMatrixZigZag(m);
        }
    
        public static void printMatrixZigZag(int [][] matrix){
            int tR = 0;
            int tC = 0;
            int dR = 0;
            int dC = 0;
            int endR = matrix.length-1;
            int endC = matrix[0].length-1;
            boolean flag=false;
            while (tR!=matrix.length){
                printZigZag(matrix,tR,tC,dR,dC,flag);
                tC=tC==endC?tC:tC+1;
                tR= tC==endC ?tR+1:tR;
                dR=dR==endR?dR:dR+1;
                dC=dR==endR?dC+1:dC;
                flag=!flag;
            }
        }
    
        public static void printZigZag(int [][] matrix,int tR,int tC,int dR,int dC,boolean flag ){
            if(flag){
                while (tR!=dR+1){
                    System.out.print(matrix[tR++][tC--]+" ");
                }
            }else {
                while (dR!=tC-1) {
                    System.out.print(matrix[dR--][dC++]+" ");
                }
            }
        }
    }
    

    自然数数组的排序

    给定一个长度为N的整型数组arr,其中有N个互不相等的自然数1N,请实现arr的排序,但是不要把下标0N-1位置上的数值通过直接赋值的方式替换成1~N。

    要求:时间复杂度为O(N),额外空间复杂度为O(1)。

    思路:

    1.从左向右遍历arr,假设当前遍历到i位置。

    2.if arr[i]==i+1,不需要调整,继续遍历。

    3.if arr[i]!=i+1,进行调整。

    根据调整功能的方法不同,可以有不同的实现过程。

    public class CircleDynamic {
        public static void main(String [] args){
            int [] m= {1,2,5,3,  4};
            m=sort(m);
            for(int i=0;i<m.length;i++){
                System.out.println(m[i]);
            }
        }
    
        public static int [] sort(int [] matrix){
           for(int i=0;i<matrix.length;i++){
               while(matrix[i]!=i+1){
                   int temp=matrix[matrix[i]-1];
                   matrix[matrix[i]-1]=matrix[i];
                   matrix[i]=temp;
               }
           }
           return matrix;
        }
    }
    

    奇数下标都是奇数或偶数下标都是偶数

    给定一个长度不小于2的数组arr,实现一个函数调整arr,要么使所有的偶数下标都是偶数,要么使所有的奇数下标都是奇数。

    要求:时间复杂度为O(N),额外空间复杂度为O(1)。

    算法解释:

    最后位置的数是偶数,就替换前面的偶数下标,最后位置的是奇数,就替换前面的奇数下标,每替换一次,最后位置的数都是变化的,这样就都替换了。

    public class CircleDynamic {
        public static void main(String [] args){
            int [] m= {1,8,3,2,4,6};
            modify(m);
        }
    
        public static  void  modify(int [] matrix){
           if(matrix==null || matrix.length<2){
               return;
           }
            int even=0;
           int odd=1;
           int end=matrix.length-1;
           while (even<=end && odd<=end){
               if((matrix[end]&1)==0){
                   swap(matrix,even,end);
                   even+=2;
               }else {
                   swap(matrix,odd,end);
                   odd+=2;
               }
           }
            for(int i=0;i<matrix.length;i++){
                System.out.println(matrix[i]);
            }
    
        }
    
        public static void swap(int [] m,int index1,int index2){
            int temp=m[index1];
            m[index1]=m[index2];
            m[index2]=temp;
        }
    }
    

    子数组的最大累加和问题

    给定一个数组,返回子数组的最大累加和。

    例如:arr=[1,-2,3,5,-2,6,-1],所有子数组中,[3,5,-2,6]可以累加出最大的和12,return 12.

    时间复杂度为O(N),额外空间复杂度为O(1)。

    如果arr中没有正数,产生的最大累加和一定是数组中的最大值。

    如果arr中有正数,从左向右遍历arr,用变量cur记录每一步的累加和,遍历到正数cur增加,遍历到负数cur减少。当cur<0时,舍弃当前部分,令cur=0,表示重新从下一个数开始累加。当cur>=0时,每一次的累加都可能是最大的累加和,所以,用另外一个变量max全程跟踪cur出现的最大值。

    cur累加到负数就重新累加,max记录当前cur的最大值。

    public class CircleDynamic {
        public static void main(String [] args){
            int [] m= {1,-2,3,5,-2,6,-1};
            maxSum(m);
        }
    
        public static void maxSum(int[] m){
            if(m==null||m.length==0){
                return;
            }
            int cur=0;
            int max=0;
            for(int i=0;i<m.length;i++){
                cur+=m[i];
                if(max<cur){
                    max=cur;
                }
                if(cur<0){
                    cur=0;
                }
            }
            System.out.println(max);
        }
    }
    

    子矩阵的最大累计和问题

    给定一个矩阵,其中的值有正、有负、有0。返回子矩阵的最大累计和。

    如果一个矩阵一共有K行且限定必须含有K行元素的情况下,只要把矩阵中每一行的K个元素累加生成一个累加数组,然后求出这个数组的最大累加和,这个最大累加和就是必须含有K行元素的子矩阵中的最大累加和。

    用i动态测试每一层往下累计的最大值,i+1实际上是把i层之上的全部不算。实现动态遍历

    j和k是普通遍历

    用s[k]存每次往下加的数字

    cur加s[k]如果大就保存,如果不是最大就不存,如果小于0就清零。

    public class Main {
        public static void main(String[] args) {
            int[][] m = {{-90, 48, 78},
                         {64, -40, 64},
                         {-81, -7, 66}};
            maxSum(m);
        }
    
        public static void maxSum(int[][] m) {
            if (m == null || m.length == 0 || m[0].length == 0) {
                return;
            }
            int cur = 0;
            int max = Integer.MIN_VALUE;
            int []s=null;
            for (int i = 0; i < m.length; i++) {
                 s = new int[m[0].length];
                for (int j = i; j < m.length; j++) {
                    cur = 0;
                    for (int k = 0; k < m[0].length; k++) {
                        s[k] += m[j][k];
                        cur += s[k];
                        max = Math.max(max, cur);
                        if (cur < 0) {
                            cur = 0;
                        }
                    }
                }
            }
            System.out.println(max);
        }
    }
    

    在数组中找到一个局部最小的位置

    定义局部最小的概念。arr长度为1时,arr[0]是局部最小。arr的长度为N(N>1)时,如果arr[0]<arr[1],那么arr[0]为局部最小。如果arr[N-1]<arr[N-2],那么arr[N-1]是局部最小。如果0<i<N-1,arr[i]<arr[i+1]&&arr[i]<arr[i-1],那么arr[i]是局部最小。

    给定无序数组arr,已知arr中任何两个相邻的数不相等。写一个函数,只需返回arr中任何一个局部最小出现的位置即可。

    利用二分查找可以做到时间复杂度O(logN)、额外空间复杂度为O(1)

    public class Main {
        public static void main(String[] args) {
            int[] m = {90,78, 48, 78};
            System.out.println(getLessIndex(m));
        }
    
        public static int getLessIndex(int[] arr) {
            if(arr==null || arr.length==0){
                return -1;
            }
            if(arr[0]<arr[1]){
                return 0;
            }
    
            if(arr[arr.length-1]<arr[arr.length-2]){
                return arr[arr.length-1];
            }
    
            int left = 1;
            int right= arr.length-2;
            int mid=0;
            while (left<right){
                mid=(right+left)/2;
                if(arr[mid]>arr[mid-1]){
                    right=mid-1;
                }else if(arr[mid]>arr[mid+1]){
                    left=mid+1;
                }else {
                    return mid;
                }
            }
            return left;
                        }
                    }
    

    不包含本位置值的累乘数组

    给定一个整型数组,返回不包含本位置的累乘数组。

    例如:arr=[2,3,1,4],返回[12,8,24,6],即除自己外,其他位置的类乘。

    1.时间复杂度为O(N).

    2.除需要返回的结果数组之外,额外空间复杂度为O(1).

    使用除法:

    结果数组记为res,所有数的乘积记为all。如果数组中不含0,则设置res[i]=all/arr[i]。如果数组中有一个0,对唯一的arr[i]==0的位置令res[i]=all,其他位置都是0。如果数组中0的数量大于1,那么res所有位置上的值都是0。

    不使用除法:

    1.生成两个长度和arr一样的新数组lr[]和rl[],lr[i]=arr[0…i],rl[i]=arr[i…N-1]。

    2.res[i]=lr[i-1]*rl[i+1]

    3.res[0]=rl[1],res[N-1]=lr[N-2]

    这里又额外使用了两个数组,可以通过res数组复用的方式省略掉这两个数组,先把res数组作为辅助计算的数组,然后把res调整成结果数组返回。

    public class Main {
        public static void main(String[] args) {
            int[] m = {2,3, 1, 4};
           m= product(m);
            for(int i=0;i<m.length;i++){
                System.out.println(m[i]);
            }
        }
    
        public static int [] product(int[] arr) {
            if(arr==null || arr.length==0){
                return null;
            }
           int[] res=new int [arr.length];
            res[arr.length-1]=1;
            for(int i=arr.length-2;i>=0;i--){
                res[i]=res[i+1]*arr[i+1];
            }
            int temp=1;
            for(int i=0;i<arr.length;i++){
                res[i]*=temp;
                temp*=arr[i];
    
            }
                return res;
                        }
                    }
    

    求最短通路值

    用一个整形矩阵matrix表示一个网络,1代表有路,0代表没路,每一个位置只要不越界,都有上下左右4个方向,求从最左上角到最右下角的最短通路值。

    例如:

    1 0 1 1 1

    1 0 1 0 1

    1 1 1 0 1

    0 0 0 0 1

    通路只有1条,由12个1组成,所以返回12。

    使用宽度优先遍历即可,如果矩阵大小为NM,时间复杂度为O(NM),

    1.开始时生成map矩阵,map[i][j]的含义是从(0,0)位置走到(i,j)位置最短的路径值。然后将左上角位置(0,0)的行坐标和列坐标放入行队列rQ、列队列 cQ。

    2.不断从队列弹出一个位置(r,c),然后看这个位置的上下左右四个位置哪些在matrix上的值是1,这些都是能走的位置。

    3.将那些能走的位置设置好各自在map中的值,即map[r][c]+1。同时将这些位置加入到rQ和cQ的中,用队列完成宽度优先遍历。

    4.在步骤3中,如果一个位置走过,就不要重复走,这个逻辑可以根据一个位置在map中的值来确定,比如map[i][j]!=0,就可以知道这个位置之前走过。

    5.一直重复步骤2~步骤4。直到遇到右下角位置,说明已经找到终点,返回终点在map中的值即可,如果rQ和cQ已经为空都没有遇到终点位置,return 0。

    import java.util.LinkedList;
    import java.util.Queue;
    public class Main {
        public static void main(String[] args) {
           int[][] m = { {1,0,1,1,1},
                         {1,0,1,0,1},
                         {1,1,1,0,1},
                         {0,0,0,0,1} };
                System.out.println(minPathValue(m));
        }
    
        public static int minPathValue(int [][] m){
            if(m==null || m.length==0|| m[0].length==0||m[0][0]!=1||m[m.length-1][m[0].length-1]!=1){
                return 0;
            }
            int res=0;
            int [][] map=new int [m.length][m[0].length];
            map[0][0]=1;
            Queue<Integer> rQ=new LinkedList<Integer>();
            Queue<Integer> cQ=new LinkedList<Integer>();
            rQ.add(0);
            cQ.add(0);
            int r=0;
            int c=0;
            while (!rQ.isEmpty()){
                r=rQ.poll();
                c=cQ.poll();
                if( ( r==m.length-1 ) && ( c==m[0].length-1)){
                    //查map路径
                    for(int i=0;i<map.length;i++){
                        for (int j=0;j<map[0].length;j++){
                            System.out.print(map[i][j]+"  ");
                        }
                        System.out.println(" ");
                    }
                      //输出结果
                    return map[r][c];
                }
                walkTo(map[r][c],r-1,c,m,map,rQ,cQ);
                walkTo(map[r][c],r+1,c,m,map,rQ,cQ);
                walkTo(map[r][c],r,c-1,m,map,rQ,cQ);
                walkTo(map[r][c],r,c+1,m,map,rQ,cQ);
            }
            return res;
        }
    
        public static void walkTo(int pre,int toR,int toC ,int [][]m , int [][] map,Queue<Integer>  rQ , Queue<Integer>  cQ ){
            if (toR < 0 || toR == m.length || toC < 0 || toC == m[0].length || m[toR][toC] != 1 || map[toR][toC] != 0) {
                return;
            }
            map[toR][toC]=pre+1;
            rQ.add(toR);
            cQ.add(toC);
            }
        }
    
    
    ---res:
    1  0  7  8  9   
    2  0  6  0  10   
    3  4  5  0  11   
    0  0  0  0  12   
      
    12
    

    最长的可整合数组的长度

    如果一个数组再排序之后,每相邻两个数差的绝对值都为1,则该数组为可整合数组。例如,[5,3,4,6,2]排序之后为[2,3,4,5,6],符合每相邻两个数差的绝对值为1,所以这个数组为可整合数组。

    给定一个整型数组,请返回其中最大可整合子数组的长度。例如,[5,5,3,2,6,4,3]的最大可整合子数组为[5,3,2,6,4],所以返回5.

    一个数组中如果没有重复元素,并且如果最大值减去最小值,再加上1的结果等于元素的个数(max-min+1=元素个数),那么这个数组就是可整合数组。

    这样,验证一个数组是否是可整合数组的时间复杂度可以从第一种方法的O(NlogN)减少至O(1),整个过程的时间复杂度为O(N^2)

    无需排序,仅仅只需要遍历比较大小

    public class Main {
        public static void main(String[] args) {
            int[] m = {  5,5,3,2,6,4,3};
    
            System.out.println(getLIL(m));
        }
    
        public static int getLIL(int [] arr){
            if(arr.length==0||arr==null){
                return 0;
            }
            int max=0;
            int min=0;
            int len=0;
            HashSet<Integer> set=new HashSet<Integer>();
            for(int i=0;i<arr.length;i++){
                max=Integer.MIN_VALUE;
                min=Integer.MAX_VALUE;
                for(int j=i;j<arr.length;j++){
                    if(set.contains(arr[j])){
                        break;
                    }
                    set.add(arr[j]);
                    max=Math.max(max,arr[j]);
                    min=Math.min(min,arr[j]);
                    if(max-min==j-i){
                        len=Math.max(len,j-i+1);
                    }
                }
                set.clear();
            }
            return len;
        }
     }
    

    边界都是1的最大正方形大小

    给定一个M*N的矩阵,在这个矩阵中,只有0和1两种值,返回边框全是1的最大正方形的边长长度。

    例如:

    ​ [0, 1, 1, 1, 1],

    ​ [0, 0, 1, 0, 1],

    ​ [0, 1, 1, 0, 1],

    ​ [0, 1, 1, 1, 1],

    ​ [0, 1, 0, 1, 1]

    其中,边框全是1的最大正方形的大小为4。

    解析:

    1.正方形边长为0<=size<=Math.min(rows,cols);

    2.边长为size时,左上角的坐标范围为 0<=i<=rows-size,0<=j<=cols-size;

    3.使用预处理矩阵right和down,空间换时间,right[i][j]保存matrix[i][j]包括自己往右边有多少个1,同理down[i][j]。

    3.对每一个左上角的边长为size的矩形判断边上是否全为1,发现有满足的直接返回当前size。

    public class Main {
        public static void main(String[] args) {
           int[][] arr = { {0,1,1,1,1},
                           {0,1,0,0,1},
                           {0,1,0,0,1},
                           {0,1,1,1,1},
                           {0,1,0,1,1}};
           System.out.println(getMaxSize(arr));
        }
    
        public static int getMaxSize(int [][]m){
            int [][] right=new int [m.length][m[0].length];
            int [][] down= new int [m.length][m[0].length];
            setBorderMap(m,right,down);
            for(int size=Math.min(m.length,m[0].length);size!=0;size--){
                if(hasSizeOfBorder(size,right,down)){
                    return size;
                }
            }
            return 0;
        }
    
        public static void setBorderMap(int [][] m,int [][]right ,int [][]down){
            int r=m.length;
            int c=m[0].length;
            if(m[r-1][c-1]==1){
                right[r-1][c-1]=1;
                down[r-1][c-1]=1;
            }
    
            for(int i=r-2;i>=0;i--){
                if(m[i][c-1]==1){
                    right[i][c-1]=1;
                    down[i][c-1]=down[i+1][c-1]+1;
                }
            }
    
            for(int j=c-2;j>=0;j--){
                if(m[r-1][j]==1){
                    right[r-1][j]=right[r-1][j+1]+1;
                    down[r-1][j]=1;
                }
            }
    
            for(int i=r-2;i>=0;i--){
                for (int j=c-2;j>=0;j--){
                    right[i][j]=right[i][j+1]+1;
                    down[i][j]=down[i+1][j]+1;
                }
            }
        }
    
        public static boolean hasSizeOfBorder(int size ,int [][]right ,int [][] down){
            for(int i=0;i<right.length-size+1;i++){
                for(int j=0;j<right[0].length-size+1;j++){
                    if(right[i][j]>=size&&down[i][j]>=size
                            &&right[i+size-1][j]>=size
                            &&down[i][j+size-1]>=size)
                        return true;
                }
            }
            return false;
        }
    }
    

    需要排序的最短子数组长度

    package Array;
    
    /**
     * Created by zdmein on 2017/9/15.
     *    需要排序的最短子数组长度
     *    思路:
            用noMin  记录从右到左,可以遍历的,最左边开始需要重新排的
            用noMax   记录从左到右,可以遍历的,最右边需要重新排的
    
     1,   5,3,4,2,  6,7
     返回  4
     */
    public class getMinLength1 {
        public static void main(String args[]){
            int []arr={1,5,3,4,2,6,7};
            System.out.println(getMinLength(arr));
        }
    
        public static int getMinLength(int [] arr){
            if(arr==null||arr.length<2){
                return 0;
            }
    
            int min=arr[arr.length-1];
            int noMin=-1;
            for(int i=arr.length-2;i>=0;i--){
                if(arr[i]>min){
                    noMin=i;
                }else {
                    min=Math.min(arr[i],min);
                }
            }
            if(noMin==-1)
                return 0;
    
            int max=arr[0];
            int noMax=-1;
            for(int i=1;i<arr.length;i++){
                if(arr[i]<max){
                    noMax=i;
                }else {
                    max=Math.max(max,arr[i]);
                }
            }
    
            return noMax-noMin+1;
        }
    
    }
    

    Learn ,Practice ,Summary !
  • 相关阅读:
    爬虫|如何在Pycharm中调试JS代码
    nexus 6p 输入8.1和获取root权限
    年近30的我,离开了北京,回家做个老百姓,等待那一刻的发生!
    Azure认知服务的实际应用-资讯采集推送
    C#类库推荐 拼多多.Net SDK,开源免费!
    [翻译]EntityFramework Core 2.2 发布
    4-如何学习和解决问题
    3-WIN10系统及开发工具支持
    2-选择学习的目标和方向
    1-编程的基本条件和起步
  • 原文地址:https://www.cnblogs.com/daminzhou/p/8387099.html
Copyright © 2011-2022 走看看