• 剑指offer第二版面试题2:数组中重复的数字(JAVA版)


    题目:在一个长度为n+1的数组里的所有数字都在1~n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但是不能修改输入的数组。例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应的输出是重复的数字2或者3。

    方法1:利用辅助函数,逐一把原数组的每个数字复制到辅助数组。如果原数组中被复制的数字是m,则把它复制到辅助数组中下标为m的位置。如果下标为m的位置上已经有数字了,则说明该数字重复了。由于使用了辅助空间,故该方案的空间复杂度是O(n) 

    public class Test1 {
        public static int getReNum(int[] arr){
            //传入参数出错
            if(arr==null || arr.length==0){
                return -1;
            }
            for(int i=0;i<arr.length;i++){
                if(arr[i]<=0 || arr[i]>arr.length){
                    return -1;
                }
            }
            //辅助数组
            int[] temp=new int[arr.length];
            for(int i=0;i<arr.length;i++){
                if(temp[arr[i]]==arr[i]){
                    return arr[i];
                }else{
                    temp[arr[i]]=arr[i];
                }
            }
            return -1;
        }
        
        public static void main(String[] args) {
            int arr[]=new int[]{5,4,3,6,2,1,2};
            int reNum = getReNum(arr);
            System.out.println(reNum);
        }
    }

    方法二:类似二分法

      由于分析一的空间复杂度是O(n),因此我们需要想办法避免使用辅助空间。我们可以这样想:如果数组中有重复的数,那么n+1个1~n范围内的数中,一定有几个数的个数大于1。那么,我们可以利用这个思路解决该问题。我们把从1~n的数字从中间的数字m分为两部分,前面一半为1~m,后面一半为m+1~n。如果1~m的数字的数目等于m,则不能直接判断这一半区间是否包含重复的数字,反之,如果大于m,那么这一半的区间一定包含重复的数字;如果小于m,另一半m+1~n的区间里一定包含重复的数字。接下来,我们可以继续把包含重复的数字的区间一分为二,直到找到一个重复的数字。

    public class Test2 {
        //传入一个数组,从开始位置和结束位置,有多少个数字
        public static int getCount(int arr[],int start,int end){
            int count=0;
            for(int i=0;i<arr.length;i++){
                if(arr[i]>=start && arr[i]<= end){
                    count++;
                }
            }
            return count;
        }
        //查找重复的数字
        public static int getReNum(int arr[]){
            //传入数组不合法
            if(arr.length==0 || arr==null){
                return -1;
            }
            for(int i=0;i<arr.length;i++){
                if(arr[i]<=0 || arr[i]>=arr.length){
                    return -1;
                }
            }
            
            int start=1;
            int end=arr.length-1;
            int mid=0;
            int count=0;
            while(end>=start){
                if(start==end){
                    count=getCount(arr, start, end);
                    if(count>1){
                        return start;
                    }else{
                        break;
                    }
                }
                mid = (start + end) / 2;
                count = getCount(arr, start, mid);
                if (count > mid - start + 1) {
                    end = mid;
                } else {
                    start = mid + 1;
                }
            }
            return -1;
        }
        
        public static void main(String[] args) {
            int[] numbers = { 1, 3, 5, 4, 2, 1, 6, 7 };
            int reNum = getReNum(numbers);
            System.out.println(reNum);
        }
    }
  • 相关阅读:
    第九章 ZYNQ-MIZ701 片上ADC的使用
    第八章 ZYNQ-MIZ701 软硬调试高级技巧
    第七章 ZYNQ-MIZ701 GPIO使用之EMIO
    第六章 ZYNQ-MIZ701 GPIO使用之MIO
    第十章 MIZ702 ZYNQ制作UBOOT固化程序
    bzoj1070 [SCOI2007]修车
    bzoj1449 [JSOI2009]球队收益
    bzoj2007 [Noi2010]海拔
    bzoj1001 [BeiJing2006]狼抓兔子
    网络流的一类经典问题--二元费用问题
  • 原文地址:https://www.cnblogs.com/xhlwjy/p/11255257.html
Copyright © 2020-2023  润新知