给定一个长度为 n+1 的数组nums,数组中所有的数均在 1∼n 的范围内,其中 n≥1。
请找出数组中任意一个重复的数,但不能修改输入的数组。
样例
给定 nums = [2, 3, 5, 4, 3, 2, 6, 7]。
返回 2 或 3。
思考题:如果只能使用 O(1) 的额外空间,该怎么做呢?
算法(分治,二分)O(nlogn)
每个数都会对应一个位置nums[i] = i;
题目给出n + 1个数,但是只有n个位置,由抽屉原理,必定有一个位置会放两个数;所以可以通过二分来不断缩小答案所在的区间来找到答案;
每次分为两个区间[l,mid],[mid+1,r],然后遍历数组统计有多少个数的数值是在l~mid之间,如果count > mid - l + 1,说明答案在区间;直到区间长度为1时就是答案
时间复杂度:二分每次区间缩短一半,logn,每次遍历数组O(n),所以是nlogn;
由于没有开辟新的数组,空间复杂度O(1);
C++代码
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
int l = 1, r = nums.size() - 1;
while(l < r){
int mid = l + r >> 1;
int s = 0;
for(auto x : nums) s += x >= l && x <= mid;
if(s > mid - l + 1) r = mid;
else l = mid + 1;
}
return r;
}
};