数的取值范围是[1, n],取n + 1个组成一个大小为n+1的数组
1)根据鸽巢原理,必然有一个重复的
2)求这个重复的数
思路一:桶大小为1的桶排序,值和位置一一对应,尝试把每个值放到它对应的位置上,如果某个值不在其位置上,且其位置上已经是这个值,说明这个值重复
int findDuplicate(vector<int>& nums) {
for (int i = 0; i < nums.size(); ++i) {
while (nums[i] != i + 1 && nums[nums[i] - 1] != nums[i]) {
swap(nums[i], nums[nums[i] - 1]);
}
if (nums[i] != i + 1) return nums[i];
}
}
思路二:二分,这个重复值要么落在[l, m],要么在[m + 1, r]
int findDuplicate(vector<int>& nums) {
auto countInRange = [&](int l, int r)->int {
int count = 0;
for_each(nums.begin(), nums.end(), [&](int e)->void{if (e >= l && e <= r) ++count;});
return count;
};
int l = 1, r = nums.size() - 1;
for (; l < r; ) {
int m = l + (r - l) / 2;
if (countInRange(l, m) > m - l + 1) r = m;
else l = m + 1;
}
return l;
}