前面兩篇文章主要介紹了,快慢指針在鏈表環中的應用。除此之外,我們還常常利用快慢指針來查找單向鏈表中指定位置的節點。
常見的經典題目有:
1、查找倒數i位置的的節點
2、查找中間節點
我們依次來看
一、查找快慢指針查找單鏈表中位於倒數第i個位置的元素
力扣 劍指 Offer 22. 鏈表中倒數第k個節點 (https://leetcode.cn/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/)
如果沒有提前做過準備,想要解決類似問題,只能通過緩存等方式來解決。但是通過快慢指針,可以很巧妙的解決該問題。
思路是這樣的:(防盜連接:本文首發自http://www.cnblogs.com/jilodream/ )
快慢指針同時指向head節點。接着慢指針不動,快指針向前移動i步。之後快慢指針同速前移動。直至快指針先到終點,此時慢指針,所處的位置就是倒數第i個節點的位置。
就像下圖,假設右側小人先跑40m,隨後兩者同速前進,則左側小人距離右側小人始終爲40m。這樣當右側小人到達終點時,左側小人的位置恰好爲倒數40m處:
代碼也很簡單:
1 public ListNode getKthFromEnd(ListNode head, int k) { 2 ListNode fast = head; 3 ListNode tail = head; 4 for (int i = 0; i < k-1; i++) { 5 fast = fast.next; 6 } 7 while (fast.next != null) { 8 fast = fast.next; 9 tail = tail.next; 10 } 11 return tail; 12 }
這個場景其實除了雙指針的解法,還可以通過遞歸出棧的方式解決,感興趣的同學可以自己想想
二、查找鏈表中間位置的節點
力扣 876. 鏈表的中間結點 (https://leetcode.cn/problems/middle-of-the-linked-list/)
此題與上題類似,仍然可以採用快慢指針的形式。
區別是不再同速保持固定距離,而是快指針每次走兩步,慢指針走一步。
這樣假設快指針遍歷了2N個節點,慢指針就是便宜了N個節點。
如果你自己考慮這個問題,你會發現事情沒有這麼簡單:
這裏會涉及到兩個問題:(防盜連接:本文首發自http://www.cnblogs.com/jilodream/ )
1、鏈表長度是不是偶數。
2、鏈表如果是偶數,那麼中間節點應該是中間位置左側節點 還是右側節點。
如果鏈表長度奇數的話,那麼要注意快指針最後一次移動是不能走兩步的。
如果鏈表長度是偶數的話,我們取中間位置的右側節點。代碼如下:
1 public ListNode middleNode(ListNode head) { 2 ListNode fast = head; 3 ListNode low = head; 4 while (true) { 5 if (fast.next == null) { 6 return low; 7 } 8 low = low.next; 9 fast = fast.next; 10 if (fast.next != null) { 11 fast = fast.next; 12 } 13 } 14 }
細想一下,這種思路其實除了可以找到中間節點位置,還可以找到1/3處節點位置,1/5處節點位置。