面试题3.2:不修改数组找出重复的数字
题目描述:在一个长度n+1的数组里的所有数字都在1~n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。
例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应的输出是重复的数字2或者3。
解法一:利用辅助数组
创建一个长度为n+1的辅助数组,将原数组的每个下标处元素的值作为辅助数组的下标,并使辅助数组的下标处元素的值加1,当值大于1时,说明出现重复。
新数组:
索引 值
0 0
1 0
2 0
3 0
4 0
5 0
当找到第一个重复元素3时
新数组:
索引 值
0 0
1 0
2 1
3 1
4 1
5 1
到第5个下标时,
索引3 --> 2 说明此时原数组下标i处产生了重复元素。
此方法需要使用额外空间O(N)。
解法二:二分查找,分致思想。
根据题目描述,长度为8的数组,所有数字都在1~7之间。使用中间数字4,将1~7分成两段,一段是1~4,一段是5~7。
统计1~4这4个数组在数组中出现的次数,如果>4次,说明重复的数字就在这段区域,再继续二分。如果<4次,则在另一段区间,对另一段区间进行二分。
public static int getDuplication(int[] nums) { if (nums == null || nums.length < 0) { return -1; } int start = 1; int end = nums.length - 1; while (start <= end) { int mid = ((end - start) >> 1) + start; int count = 0; //寻找该区间数字在数组中出现的次数 for (int num : nums) { if (num >= start && num <= mid) { count++; } } //区间只剩一个数字 if (end == start) { //如果该数字出现了两次,就是重复 if (count > 1) { return start; } else { break; } } //如果该区间中元素出现的个数,大于区间的最大值,说明该区间存在重复的数字 if (count > mid - start + 1) { //在分割后的左边区间内 end = mid; } else { //在分割后的右边区间 start = mid + 1; } } return -1; }
学习的博客多用于在笔记中,防止笔记过于臃肿,所以将样例及运行结果放在博客中,后以超链接的形式记录在笔记中,所以有些博文过于单薄。如果有小伙伴遇到问题欢迎评论,看到就会回复,学渣一枚,加油努力。