鏈表問題常用套路之——快慢指針
概述
使用多個指針是解決鏈表問題的常用套路(諸如反轉鏈表需要三個指針前中后等),其中有兩個比較特殊的指針分別是slow指針和fast指針,也叫快慢指針。
原理
快慢指針顧名思義,即一個移動的比較快的指針和一個移動的比較慢的指針。
實際運用中可以這么寫:
slow = slow.next;
fast = fast.next.next;
假設快慢指針原來都指向頭結點,這樣的話,fast指針移動速度就是slow指針的兩倍,這是很有用的設計。
用途
舉兩個例子來說明快慢指針的用途.
1.找到鏈表中點
快慢指針可以很快的找到鏈表的中點。在不知道鏈表長度的情況下,找到鏈表的中點,一個比較慢的方法是下面這樣做。
int length = 0;
ListNode node = head;
// 遍歷一遍鏈表得到鏈表長度
while(node!=null){
node = node.next;
length ++;
}
// 根據得到的鏈表長度,可以遍歷長度/2次來找到終點
ListNode centerNode = head;
for(int i=0;i<length/2-1;i++){
centerNode = centerNode.next;
}
上面的方法遍歷了N+N/2次,且代碼略顯復雜,最后遍歷長度/2次時,要注意centerNode節點實際上是中點的下一個節點,所以可以讓遍歷次數-1來得到中點.
下面是使用了快慢節點的做法:
// 快慢指針起點相同
ListNode slow = head;
ListNode fast = head;
while(fast.next!=null && fast.next.next!=null){
slow = slow.next;
// 快指針移動速度為慢指針兩倍
fast = fast.next.next;
}
// 當快指針到達鏈表表尾時,此時慢指針指向鏈表中點
ListNode centerNode = slow;
可以看到,上述代碼僅遍歷N/2此就找到了鏈表的中點.
例題:
判斷回文鏈表:https://leetcode-cn.com/explore/interview/card/top-interview-questions-easy/6/linked-list/45/
問題要求O(N)時間復雜度與O(1)空間復雜度,思路是:
1. 找到鏈表中點
2. 根據中點將鏈表掰成前后兩段
3. 對鏈表后段進行翻轉
4. 根據鏈表前段和經過翻轉后的后段來判斷回文
找中點的過程即可以使用快慢指針來查找.
2.鏈表判環
判斷一個鏈表中是否有環,使用快慢指針思路會非常簡單.
簡單來說,就是,讓快慢指針起點相同,快指針移動速度是慢指針兩倍,當快指針與慢指針相遇的時候說明此鏈表有環,否則沒環.
例題:
環形鏈表:https://leetcode-cn.com/explore/interview/card/top-interview-questions-easy/6/linked-list/46/