一、题目
在一个长度为n+1的数组里的所有数字都在1~n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应的输出是重复的数字2或者数字3。
二、代码实现
1.思考过程
使用二分查找,时间复杂度O(nlogn)。不允许使用额外空间,也不允许修改原数组,因而无法排序。但是题中限定数据范围为[1,n],而序列1,2,...,n是有序的,因而可以在[1,n]中进行二分查找,注意不是在nums数组中进行查找。mid = (1+n)/2,接下来判断最终答案是在[1,mid]中还是在[mid+1,n]中。为了 缩小区间,需要统计原数组中小于等于mid的元素个数,记为count。如果count > mid, 根据鸽巢原理,在 [1,mid] 范围内的数字个数超过了 mid ,所以区间中[1, mid]一定有一个重复数字,保留区间[1, mid]。否则重复元素在[mid + 1, n]中,切除区间[mid + 1, n]。最终两个指针的值即为重复数字!
2.代码
代码如下(示例):
int duplicationInArray(vector<int> & nums)
{
if(nums.empty())
return -1;
int n = nums.size;
int l = 1, r = n;
while(l < r)
{
int mid = (l + r) >> 1;
int cnt = 0;
for (int i = 0; i < n; ++i) // 统计原数组中 <= mid 的元素个数
if (nums[i] <= mid)
++cnt;
if (cnt > mid) // 重复数字在区间[1,mid] 中
r = mid;
else // 重复数字在区间[mid+1, n]中
l = mid + 1;
}
reutrn l;
}
总结
- 考查对二分查找算法的理解,并能快速、正确地实现二分查找算法的代码;
- 考查沟通能力。