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 !
  • 相关阅读:
    C++ 将对象写入文件 并读取
    IronPython fail to add reference to WebDriver.dll
    How to Capture and Decrypt Lync Server 2010 TLS Traffic Using Microsoft Tools
    .net code injection
    数学系学生应该知道的十个学术网站
    Difference Between Currency Swap and FX Swap
    Swift开源parser
    谈谈我对证券公司一些部门的理解(前、中、后台)[z]
    JDK8记FullGC时候Metaspace内存不会被垃圾回收
    JVM源码分析之JDK8下的僵尸(无法回收)类加载器[z]
  • 原文地址:https://www.cnblogs.com/daminzhou/p/8387099.html
Copyright © 2011-2022 走看看