用vs做網(wǎng)站的登錄百度關(guān)鍵詞搜索量統(tǒng)計
一、題目
給定一個長度為?n+1?的數(shù)組nums
,數(shù)組中所有的數(shù)均在?1~n1?的范圍內(nèi),其中?n≥1。
請找出數(shù)組中任意一個重復(fù)的數(shù)。
樣例
給定 nums = [2, 3, 5, 4, 3, 2, 6, 7]。返回 2 或 3。
二、解析
解決這個問題的一種有效方法是使用快慢指針,也稱為龜兔賽跑算法(Floyd's Cycle Detection Algorithm)。該算法的基本思想是在一個循環(huán)鏈表中,快指針和慢指針分別以不同的速度移動,如果存在環(huán),則兩者最終會相遇。
在這個問題中,可以將數(shù)組視為一個鏈表,數(shù)組中的元素值作為下一個節(jié)點(diǎn)的索引,構(gòu)成一個鏈表。因為題目保證了數(shù)組中的元素值在 1 到 n 的范圍內(nèi),所以數(shù)組中不存在負(fù)數(shù),也不存在索引超出數(shù)組范圍的情況。
原理:
當(dāng)我們把數(shù)組中的元素看作鏈表中的節(jié)點(diǎn)時,題目要求找到數(shù)組中的任意一個重復(fù)數(shù),實際上就是在鏈表中找到環(huán)的入口點(diǎn)。快慢指針?biāo)惴ǖ暮诵乃枷胧抢脙蓚€不同速度的指針,如果存在環(huán),這兩個指針最終會相遇。
下面是算法的基本思路:
-
初始化:使用兩個指針,一個慢指針
slow
和一個快指針fast
,初始時都指向數(shù)組的第一個元素nums[0]
。 -
尋找相遇點(diǎn):快指針每次前進(jìn)兩步,慢指針每次前進(jìn)一步,直到兩者相遇。相遇時,說明鏈表中存在環(huán)。
-
重置一個指針:將其中一個指針(例如慢指針)重置到數(shù)組的第一個元素
nums[0]
,而另一個指針保持在相遇點(diǎn)。 -
尋找環(huán)的入口點(diǎn):兩個指針再以相同速度前進(jìn),直到它們再次相遇。相遇點(diǎn)即為環(huán)的入口點(diǎn),也即重復(fù)的數(shù)。
這個原理的關(guān)鍵在于,當(dāng)兩個指針相遇時,說明鏈表中存在環(huán)。在尋找環(huán)的入口點(diǎn)時,將一個指針重置到鏈表頭,然后兩個指針以相同的速度前進(jìn),它們再次相遇的點(diǎn)就是環(huán)的入口點(diǎn)。在這個問題中,環(huán)的入口點(diǎn)對應(yīng)于數(shù)組中的重復(fù)數(shù)。
這個算法的時間復(fù)雜度為 O(n),其中 n 是數(shù)組的長度。算法的空間復(fù)雜度為 O(1),因為只使用了常數(shù)額外的空間。
下面是用C語言實現(xiàn)的代碼:
#include <stdio.h>int findDuplicate(int* nums, int numsSize) {// 初始化快慢指針int slow = nums[0];int fast = nums[0];// 尋找相遇點(diǎn)do {slow = nums[slow];fast = nums[nums[fast]];} while (slow != fast);// 重置其中一個指針,并尋找環(huán)的入口點(diǎn)——這里可以想一想為什么:Aslow = nums[0];while (slow != fast) {slow = nums[slow];fast = nums[fast];}// 返回環(huán)的入口點(diǎn),即重復(fù)的數(shù)return slow;
}int main() {// 示例用法int nums[] = {1, 3, 4, 2, 2};int numsSize = sizeof(nums) / sizeof(nums[0]);int duplicate = findDuplicate(nums, numsSize);printf("Duplicate: %d\n", duplicate);return 0;
}
?A:讓我們來解釋一下為什么這個過程能找到環(huán)的入口點(diǎn):
-
首次相遇點(diǎn):當(dāng)快指針和慢指針首次相遇時,它們分別走過的步數(shù)之間存在關(guān)系,快指針走過的步數(shù)是慢指針的兩倍。假設(shè)兩者相遇時,慢指針走了 k 步,則快指針走了 2k 步,其中 k 是環(huán)的長度的整數(shù)倍。
-
重置指針位置:將慢指針重置到數(shù)組的第一個元素
nums[0]
,保持快指針在相遇點(diǎn)不動。 -
再次相遇:此時,慢指針從數(shù)組頭部開始,而快指針還停留在相遇點(diǎn)。它們以相同的速度前進(jìn),當(dāng)慢指針再次走了 k 步時,快指針走了 2k 步,即正好走完了環(huán)的若干圈,同時再次相遇。
-
相遇點(diǎn)即為入口點(diǎn):再次相遇的點(diǎn)就是環(huán)的入口點(diǎn)。這是因為在第一次相遇后,慢指針已經(jīng)在環(huán)內(nèi)走了若干圈,而重置后再次相遇時,慢指針還需走若干圈才能達(dá)到入口點(diǎn),而快指針已經(jīng)在環(huán)內(nèi)等待,因此它們在入口點(diǎn)相遇。
這個過程的本質(zhì)是根據(jù)快慢指針相遇時,快指針已經(jīng)走過的步數(shù)是慢指針的兩倍的特性,找到環(huán)的入口點(diǎn)。這個算法的關(guān)鍵在于數(shù)學(xué)上的推理,而實際上這種方法是基于龜兔賽跑算法的原理。