287. Find the Duplicate Number

这题很有意思,居然可以用老朋友-二分。
1.
首先忽略要求的不可以改变数组的限制,可以这么做:
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int sz = nums.size();
while (nums[nums[0]] != nums[0])
swap(nums[nums[0]], nums[0]);
return nums[0];
}
};
因为数字从1-n,没有0,所以位置0放的一定是重复的数字。
2.当成有环的链表
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int fast = nums[nums[0]], slow = nums[0];//都是从0开始,不过需要避免第一次while判断失败
while (fast != slow) {
slow = nums[slow];
fast = nums[nums[fast]];
}
fast = 0;
while (fast != slow) {
slow = nums[slow];
fast = nums[fast];
}
return fast;
}
};
3.二分
按照之前总结的两步步来试试二分:
1.有明确的上下界:1-n
2.对于某个判断,一边可以,另一边不可以:关键就是找出这个判断条件,而这不太容易看出来。
这一题的判断是:对于所有大于等于目标数字的数字a,数组中小于等于它的数字个数要>a;对于小于目标数字的数字b,数组中小于等于它的数字个数要<=b。
为什么:比如说,只重复了两次,比如1,2,3,3,4.很明显可以看出是这样。但如果大于两个,比如1,3,3,3,4,或者1,2,3,3,3,看出依然这样。
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int lo = 1, hi = nums.size()-1;
int mid;
while (lo < hi) {
mid = lo + (hi - lo) / 2;
int cnt = 0;
for (int num : nums)
if (num <= mid)
++cnt;
if (cnt > mid)
hi = mid;
else
lo = mid + 1;
}
return lo;
}
};
所以说,以后只要最终值有明确的上下界,就尝试着找一找是不是对于某个判断,一边可以,另一边不可以,这个判读往往不太好找,需要好好想一想。但如果找出来,二分往往很好。
浙公网安备 33010602011771号