1.题目描述
在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,但是不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7,的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数组2或者3。
2.分析边界条件及测试用例
1.考虑输入数组为空,测试用例为{};
2.考虑输入数组含有大于数组规模的数,测试用例为{0,1,2,3,5};
3.考虑输入数组不重复,包含两种可能(都是小于数组规模的数,存在大于数组规模的数(2)
中包含),测试用例为{0,1,2,3,4};
3.三种解法
1.数组排序再扫描
将数组进行排序,从排好序的数组的开头进行遍历,记录当前位置与其之前位置的数,进行比较,若相等则输出该数,否则判断下一位数。
1 public static int getRepeatNumber(int[] array) { 2 // Judge the boundary of this problem 3 int len = array.length; 4 if (len == 0) {return -1;} 5 6 // solution 1 sort array then search from first to end 7 Arrays.sort(array); 8 if (array[len - 1] >= len) { 9 return -1; 10 } else { 11 int temp = array[0]; 12 int i = 1; 13 for(; i < len; i++) { 14 if (temp == array[i]) { 15 break; 16 } else { 17 temp = array[i]; 18 } 19 } 20 if (i == len) { 21 return -1; 22 } else { 23 return array[i]; 24 } 25 } 26 }
复杂度分析:时间复杂度O(nlogn),空间复杂度O(1)。
2.哈希表
对数组元素进行遍历,每次判断哈希表中是否有该元素,若有,输出此重复元素,若最后哈希表中元素数量与数组规模相等,表明无重复元素。
1 public static int getRepeatNumber(int[] array) { 2 // Judge the boundary of this problem 3 int len = array.length; 4 if (len == 0) {return -1;} 5 Set<Integer> set = new HashSet<>(); 6 int i = 0; 7 for(; i < len; i++) { 8 if (array[i] >= len) { 9 return -1; 10 } else { 11 if (set.contains(array[i])) { 12 break; 13 } else { 14 set.add(array[i]); 15 } 16 } 17 } 18 if (i == len) { 19 return -1; 20 } else { 21 return array[i]; 22 } 23 }
复杂度分析: 时间复杂度O(n),空间复杂度O(n)。
3.重排数组
从头到尾依次扫描数组中每一个数字。当扫描到第i个元素时,比较该位置数值m是否等于i。若是,接着扫描下一个数字;否则,将其与第m个数字进行比较。若相等,则返回该重复数字;否则,交换两个数字,继续重复前面的过程。
1 public static int getRepeatNumber(int[] array) { 2 // Judge the boundary of this problem 3 int len = array.length; 4 if (len == 0) {return -1;} 5 for(int i = 1; i < len;) { 6 if (array[i] >= len) { 7 return -1; 8 } else { 9 if (array[i] == i) { 10 i++; 11 } else { 12 if (array[i] == array[array[i]]) { 13 return array[i]; 14 } else { 15 int tmp = array[i]; 16 array[i] = array[array[i]]; 17 array[array[i]] = tmp; 18 } 19 } 20 } 21 } 22 return -1; 23 }
复杂度分析: 时间复杂度O(n),空间复杂度O(1)。