很绕,由于不能改数组,这种情况废弃
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { public: int findDuplicate(vector<int>& nums) { sort(nums.begin(), nums.end()); int lo = 0, hi = nums.size() - 1; while(lo < hi) { int mid = (lo + hi) / 2; if(mid + 1 <= nums[mid]) lo = mid + 1; else if(mid + 1 > nums[mid]) hi = mid; } return hi; } };
|
T(N) : O(nlogn)
S(n) : O(1)
另一种使用二分
设cnt为数组中小于等于当前元素的元素的个数,设当前mid为target
将重复的数字看作是插入到了数组中,当插入到了比target小的数中,那么设i < target
,cnt[i]必然<i,当插入到了比target大的数中,设j > target
,cnt[j]必然>j,因为多了一个比他小的cnt。
如果都正常的话,在1~target-1
区间中的数cnt[i]==i,target~n
中的数必然>j
由此,在1~n区间内进行二分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public: int findDuplicate(vector<int>& nums) { int cnt = 0; int lo = 1, hi = nums.size() - 1; while(lo < hi) { int mid = lo + (hi - lo) / 2; cnt = 0; for(auto& num : nums) cnt += num <= mid ? 1 : 0; if(cnt <= mid) lo = mid + 1; else hi = mid; } return hi; } };
|
使用cycle,有点静态链表的思想,其中的链表组成如图
image.png
由于位于0处的数字不可能是0,所以他不可能原地跳不出去。 如果碰到一个原地跳不出去的,那就说明已经是环了
最后套用142. Linked List Cycle II
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution { public: int findDuplicate(vector<int>& nums) { int walker = nums[0]; int runner = nums[0]; do { walker = nums[walker]; runner = nums[nums[runner]]; }while(walker != runner); walker = nums[0]; while(walker != runner) { walker = nums[walker]; runner = nums[runner]; } return runner; } };
|