287. Find the Duplicate Number

问题:

给定一个包含n + 1个整数的数组,其中每一个整数均介于[1, n]之间,求重复的数字。

Example 1:
Input: [1,3,4,2,2]
Output: 2

Example 2:
Input: [3,1,3,4,2]
Output: 3

Note:
You must not modify the array (assume the array is read only).
You must use only constant, O(1) extra space.
Your runtime complexity should be less than O(n2).
There is only one duplicate number in the array, but it could be repeated more than once.

  

解法1: sort,找连续两个相同的,即为所求

参考代码:

 1 class Solution {
 2 public:
 3     int findDuplicate(vector<int>& nums) {
 4         sort(nums.begin(),nums.end());
 5         for(int i=1; i<nums.size(); i++){
 6             if(nums[i]==nums[i-1]) return nums[i];
 7         }
 8         return 0;
 9     }
10 };

 

解法2: 将数组轮询,同时插入set中,每次插入前,find是否已存在,存在则为所求

 1 class Solution {
 2 public:
 3     int findDuplicate(vector<int>& nums) {
 4         unordered_set<int> tmp;
 5         for(int i:nums){
 6             if(tmp.find(i) == tmp.end()){
 7                 tmp.insert(i);
 8             }else{
 9                 return i;
10             }
11         }
12         return 0;
13     }
14 };

 

解法3: 快慢指针法:求回环相遇问题。

a:链表起点到环入口的距离。黑色
c:圆环的周长。蓝色+红色
x:相遇结点到圆环起点的距离蓝色

快结点走过的距离i为a+N1*c+x,(黑色+N1*(蓝色+红色)+蓝色

慢结点走过的距离为a+N2*c+x。(黑色+N2*(蓝色+红色)+蓝色

由于快结点的速度为慢结点的两倍(相同时间所走距离也为2倍)所以  a+N1*c+x = 2*(a+N2*c+x) 。

最后得出a+x=c(N1-2N2)。

N1代表快结点转过的圈数,N2代表慢结点转过的圈数。

a+x=N个圈的周长,即 a(黑色)=N-1个周长+(周长-x)=N-1个周长+红色

因此当快结点从链表起点出发(走黑色a的距离),慢结点以同样的速度从刚刚相遇的结点出发(走红色的距离+N-1个周长

到它们会和,会和的结点一定是重复数字的结点。(蓝色红色黑色的交点)

代码参考:

 1 class Solution {
 2 public:
 3     int findDuplicate(vector<int>& nums) {
 4         int fast=0, slow=0;
 5         fast=nums[nums[fast]];
 6         slow=nums[slow];
 7         while(fast!=slow){
 8             fast=nums[nums[fast]];
 9             slow=nums[slow];
10         }
11         fast=0;
12         while(fast!=slow){
13             fast=nums[fast];
14             slow=nums[slow];
15         }
16         return slow;
17     }
18 };

 

posted @ 2020-04-05 14:14  habibah_chang  阅读(102)  评论(0编辑  收藏  举报