【Leetcode】287. Find the Duplicate Number(快慢指針+鏈表找環的起點)

Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.

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( n 2 n^2 ).
There is only one duplicate number in the array, but it could be repeated more than once.

題目大意

給你一個數組,這個數組中只有一個重複的數字,讓你找出數組中重複的數字。其中 1 a i n u m s . s i z e ( ) 1\le a_i\le nums.size()
限制條件:

  1. 只能使用 O(1) 的空間,
  2. 不能改變原有數組
  3. 複雜度小於 O( n 2 n^2 )

解題思路

由於題目中很多的限制,所以直接排序然後判斷相鄰元素是不是相等這個算法就不可以使用了,其實這裏有一個複雜度爲 O ( n l o g ( n ) ) O(nlog(n)) 的,就是藉助二分答案然後判斷,具體不展開說了,主要說一下快慢指針的使用。
因爲給定的數組元素 1 a i n u m s . s i z e ( ) 1\le a_i\le nums.size() ,那麼我們做一個關於下標和數組元素值映射,那麼這個映射不是一對一的,是一個多對一的映射,比如說有一個數組 【1, 2, 4, 1, 3】,那麼做一個映射【{0,3}->1,1->2,2->4,4->3】,然後我們去遍歷,遍歷的規則是 x = n u m s [ x ] x=nums[x] ,那麼就有一個遍歷序列爲 { 0 , 1 , 2 , 4 , 3 , 1 } \{0,1,2,4,3,1\} ,顯然這是一個環,那麼我們要找的其實就是這個環的起點,那麼我們設置兩個指針,一個快指針fast,每次走兩步;一個慢指針slow,每次走一步,那麼肯定會在某個點相遇,這時我們將快指針fast 置爲 0 0 ,然後每次走一步,直到兩個指針相遇結束,這時相遇點就是環的起點,也是我們所求的重複的數,複雜度 O ( n ) O(n)

證明

證明1:爲什麼快慢指針在第一次一定會相遇。

1)  當快指針比慢指針慢 1 1 個單位的時候,那麼這時候快指針走兩步,慢指針走一步,正好相遇。
2)  當快指針比慢指針慢 2 2 個單位的時候,那麼這時候快指針走兩步,慢指針走一步,回到條件1)
n)  當快指針比慢指針慢 n n 個單位的時候,那麼這時候快指針走兩步,慢指針走一步,回到條件n-1)
那麼根據數學歸納法,快慢指針一定會相遇。

證明2:爲什麼快慢指針在第一次相遇時,把快指針置爲0之後,在第二次相遇時就是環的起點。

請看下圖:
在這裏插入圖片描述

因爲有 a = c a=c ,所以將快指針置爲 0 0 ,每次走一步,那麼下次快慢指針相遇的時候就是環的起點,也就是我們所求重複數的值。

代碼如下

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int slow = nums[0];
        int fast = nums[slow];
        while(slow != fast) {
            slow = nums[slow];
            fast = nums[nums[fast]];
        }
        fast = 0;
        while(slow != fast) {
            slow = nums[slow];
            fast = nums[fast];
        }
        return slow;
    }
};