尋找重複數【附java實現】

給定一個包含 n + 1 個整數的數組 nums,其數字都在 1 到 n 之間(包括 1 和 n),可知至少存在一個重複的整數。假設只有一個重複的整數,找出這個重複的數。

示例 1:

輸入: [1,3,4,2,2]
輸出: 2
示例 2:

輸入: [3,1,3,4,2]
輸出: 3
說明:

不能更改原數組(假設數組是隻讀的)。
只能使用額外的 O(1) 的空間。
時間複雜度小於 O(n2) 。
數組中只有一個重複的數字,但它可能不止重複出現一次。

來源:力扣(LeetCode)

https://leetcode-cn.com/problems/find-the-duplicate-number
拿到這個問題,我想我們第一時間會想到的一定是用桶來計數或者是使用hashmap來計數,這樣的時間複雜度只有O(n),速度還是很快的,但是有個問題就是在說明中要求額外的空間是O(1).那麼就不能使用這兩種簡單明白的方法了,這個時候我們可以考慮轉換一下思路,將這個數組問題轉換成我們熟悉的鏈表問題,也就是判斷一個鏈表是否有環,有環的話,這個環的入口在哪裏的問題。

數組中的元素都當作是鏈表上的節點,那麼有重複的數,有重複的數我們就可以看作是有環,而且這個環的入口就是這個重複的數,至於如何證明環的入口就是重複的數,我會寫個簡單的證明過程:

1.設從起點到入口的距離爲X,從入口到相遇點的距離爲L,環的周長是C

2.那麼快指針走的距離是X+nC+L,慢指針走的距離X+mC+L

3.那麼就有X+nC+L = 2(X+mC+L)->X = (n-2m)C-L

4.所以他們以相同的速度走再次相遇時肯定是在入口處

public int findDuplicate(int[] nums) {
        //將這個重複的問題抽象成環形鏈表
        //因爲快慢指針在重複的元素是成環的,環的入口就是重複的元素
        //至於這個環的入口就是重複的元素是如何推導的
        //設從起點到入口的距離爲X,從入口到相遇點的距離爲L,環的周長是C
        //那麼快指針走的距離是X+nC+L,慢指針走的距離X+mC+L
        //那麼就有X+nC+L = 2(X+mC+L)->X = (n-2m)C-L
        //所以他們以相同的速度走再次相遇時肯定是在入口處
        int slow = 0;
        int fast = 0;
        while (true) {
            slow = nums[slow];
            fast = nums[nums[fast]];
            if (slow == fast) {
                //fast指針回到開頭,兩個指針以相同速度繼續遍歷,相遇的地方就是環的入口
                fast = 0;
                while (nums[slow] != nums[fast]) {
                    slow = nums[slow];
                    fast = nums[fast];
                }
                return nums[slow];
            }
        }
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章