目錄2. 環形鍊錶ii
3. 尋找重複數
晚上刷了一道leetcode叫尋找重複數的題目,用鍊錶成環的思路實現挺有意思的,梳理下思路順便回顧下環形鍊錶
題目鏈結
這道題就是給個鍊錶讓你判斷這個鍊錶有沒有繞成環
最簡單的方法是直接用set,遍歷鍊錶並新增元素,如果鍊錶存在環,那麼入環的節點再次新增到set容器中時會失敗
public boolean hascycle(listnode head)
return false;
}
但是這種方法效率堪憂
用快慢指標,如果鍊錶有環的話,快慢指標遍歷鍊錶會在環中相遇,否則會直接結束遍歷
public boolean hascycle(listnode head)
return false;
}
這種方法效率高多了
這裡有個問題要思考一下,為什麼說鍊錶有環的話一定會在環中相遇呢?
其實可以用數學歸納法證明下,假設某一時刻慢指標也進入到環中,這時快指標肯定也早在環中轉圈圈了,快慢指標在環中相遇的過程其實可以理解為快指標追慢指標的過程,對是快指標追慢指標而不是慢指標追快指標,因為最終快慢指標相遇時,快指標一定是比慢指標多繞環走了幾圈的,假設快指標落後慢指標n步,那麼下一次時,快指標走兩步,慢指標走一步,快指標落後慢指標n-1步,再下一次落後n-2步,直到落後1步,落後0步即快指標追上慢指標。
題目鏈結
這題就是在第一題的基礎上找到那個入環的節點
和第一題一樣用set,**就不寫了
public listnode detectcycle(listnode head)
return slow;}}
return null;
}
同樣還是快慢指標的思路,按照第一題的方法先找到快慢指標在環中相遇的節點,然後快指標移到頭節點,接下來快指標和慢指標一樣也是一步一步的走,快慢指標再次相遇的點就是入環的節點。
這又是什麼道理呢?其實也很好解釋
這裡我們假設起點到入環節點的距離為x,入環節點到相遇節點的距離為z,整個環的距離為y
那麼慢指標從起點到相遇節點一共走的步數是:x + z + m * y,m為慢指標繞環的圈數
由於快指標一次走兩步,慢指標一次走一步,所以快指標從起點到相遇節點一共走的步數是:2 * (x + z + m * y)
而快指標追上慢指標的過程多饒了n圈,所以有
2 * (x + z + m * y) - (x + z + m * y) = n * y,即
x = (n - m) * y - z = (y - z) + (n - m - 1) * y, 即
x等於相遇節點到入環節點的距離加上幾圈環的距離,所以快指標移到頭節點後一步一走一定會和慢指標在入環節點再次相遇的。
題目鏈結
這題什麼意思呢,就是說有個n + 1長度的陣列,陣列裡面的元素都是1到n之間(包括1和n),所以一定會至少存在乙個重複的元素,假設只有乙個重複(可能不止重複出現一次)的整數,找出這個重複的數
題目要求:
不能更改陣列
只能用o(1)的額外空間
這題我的第一感覺就是用bitmap,但是題目限制了o(1)的空間,所以不行。
這裡可以借鑑第一題和第二題的快慢指標思路,關鍵就是要根據陣列構建出乙個鍊錶出來,其實陣列儲存的資訊無非就是某個位置的元素是幾,那我們能不能根據下標與元素值的對映關係建立鍊錶呢?
仔細想想,陣列長度為n + 1,所以下標的範圍為[0, n],陣列元素的範圍根據題意是[1, n],[1, n]在[0, n]的範圍內,所以可以這樣處理對映關係
假設陣列沒有重複的元素,以陣列[1, 3, 4, 2]為例,我們建立陣列下標n和數nums[n]的對映關係f(n),其對映關係n -> f(n)為:
0 -> 1
1 -> 3
2 -> 4
3 -> 2
我們從下標0出發,根據f(n)計算出乙個值,以這個值作為新的下標,再用這個函式計算,以此類推,可以產生乙個類似鍊錶的結構
0 -> 1 -> 3 -> 2 -> 4 -> null
如果陣列中有重複的數,以陣列[1, 3, 4, 2, 2]為例,按照同樣的方式建立的對映關係為:
0 -> 1
1 -> 3
2 -> 4
3 -> 2
4 -> 2
建立鍊錶的過程是這樣的(箭頭中間的數字表示的是第幾步)
對應的鍊錶結構為:
可以看到2 -> 4繞成了環
從理論上講,陣列中如果有重複的數,那麼就會產生多對一的對映(下標3和4都對映到陣列的元素2),這樣形成的鍊錶就一定有環了,並且環的起點就是那個重複的元素
public int findduplicate(int nums)
fast = 0;
while (fast != slow)
return slow;
}
最後上**,需要注意的是上面講的鍊錶並不真實存在的,快指標從陣列下標到陣列元素再到陣列下標,慢指標從陣列下標到陣列元素,只是快慢指標在陣列下標和陣列元素之間的移動過程其實和環形鍊錶的思路是一樣的
這題第一次接觸還是不容易想出來的,有一定的tricks,或者說叫奇技淫巧。不過也是考驗我們舉一反三知識遷移的能力,如果提示我可以通過陣列下標和陣列元素建立類似環形鍊錶的結構來處理這道題,不知道我能不能想出來呢?
LeetCode演算法題 環形鍊錶
給定乙個鍊錶,判斷鍊錶中是否有環。為了表示給定鍊錶中的環,我們使用整數 pos 來表示鍊錶尾連線到鍊錶中的位置 索引從 0 開始 如果 pos 是 1,則在該鍊錶中沒有環。示例1 輸入 head 3,2,0,4 pos 1 輸出 true 解釋 鍊錶中有乙個環,其尾部連線到第二個節點。示例 2 輸入...
leetcode系列 環形鍊錶(超級經典系列)
環形鍊錶 給定乙個鍊錶,判斷鍊錶中是否有環。為了表示給定鍊錶中的環,我們使用整數 pos 來表示鍊錶尾連線到鍊錶中的位置 索引從 0 開始 如果 pos 是 1,則在該鍊錶中沒有環。示例 1 輸入 head 3,2,0,4 pos 1 輸出 true 解釋 鍊錶中有乙個環,其尾部連線到第二個節點。示...
Leetcode刷題鍊錶之環形鍊錶
給定乙個鍊錶,判斷鍊錶中是否有環。定義兩個指標,從頭節點開始,兩個指標都向右移動,但是設定他們的移動速度不一樣,如果為環形鍊錶,則指標肯定會相遇。若為直鏈表,兩個指標至少有乙個為空。definition for singly linked list.class listnode public cla...