题目:在一个长度为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); } }
方法二:相似二分法spa
因为分析一的空间复杂度是O(n),所以咱们须要想办法避免使用辅助空间。咱们能够这样想:若是数组中有重复的数,那么n+1个1~n范围内的数中,必定有几个数的个数大于1。那么,咱们能够利用这个思路解决该问题。咱们把从1~n的数字从中间的数字m分为两部分,前面一半为1~m,后面一半为m+1~n。若是1~m的数字的数目等于m,则不能直接判断这一半区间是否包含重复的数字,反之,若是大于m,那么这一半的区间必定包含重复的数字;若是小于m,另外一半m+1~n的区间里必定包含重复的数字。接下来,咱们能够继续把包含重复的数字的区间一分为二,直到找到一个重复的数字。code
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); } }