從前往後尋找單鏈表的第k
個節點很簡單,乙個 for 迴圈遍歷過去就找到了,但是如何尋找從後往前數的第k
個節點呢?
這個解法就比較巧妙了,假設k = 2
,思路如下:
首先,我們先讓乙個指標p1
指向鍊錶的頭節點head
,然後走k
步:
現在的p1
,只要再走n - k
步,就能走到鍊錶末尾的空指標了對吧?
趁這個時候,再用乙個指標p2
指向煉表頭節點head
:
接下來就很顯然了,讓p1
和p2
同時向前走,p1
走到鍊錶末尾的空指標時前進了n - k
步,p2
也從head
開始前進了n - k
步,停留在第n - k + 1
個節點上,即恰好停煉表的倒數第k
個節點上:
這樣,只遍歷了一次鍊錶,就獲得了倒數第k
個節點p2
。
例如:力扣第 19 題「 刪除鍊錶的倒數第 n 個結點」
我的**:
class solution
while(fast!=nullptr)
slow->next=slow->next->next;
return dummy->next;}};
注意:
要使用虛擬頭節點,這樣可以省去討論許多特殊情況,返回dummy->next,head可以為空。
力扣第 876 題「 鍊錶的中間結點」就是這個題目,問題的關鍵也在於我們無法直接得到單鏈表的長度n
,常規方法也是先遍歷鍊錶計算n
,再遍歷一次得到第n / 2
個節點,也就是中間節點。
我們讓兩個指標slow
和fast
分別指向煉表頭結點head
。
每當慢指標slow
前進一步,快指標fast
就前進兩步,這樣,當fast
走到鍊錶末尾時,slow
就指向了鍊錶中點。
我的**:
class solution
}//只有乙個中間節點
return slow;}};
判斷鍊錶是否包含環屬於經典問題了,解決方案也是用快慢指標:
每當慢指標slow
前進一步,快指標fast
就前進兩步。
如果fast
最終遇到空指標,說明鍊錶中沒有環;如果fast
最終和slow
相遇,那肯定是fast
超過了slow
一圈,說明鍊錶中含有環。
當然,這個問題還有高階版:如果鍊錶中含有環,如何計算這個環的起點?
可以看到,當快慢指標相遇時,讓其中任乙個指標指向頭節點,然後讓它倆以相同速度前進,再次相遇時所在的節點位置就是環開始的位置。
為什麼要這樣呢?這裡簡單說一下其中的原理。
我們假設快慢指標相遇時,慢指標slow
走了k
步,那麼快指標fast
一定走了2k
步:
fast
一定比slow
多走了k
步,這多走的k
步其實就是fast
指標在環裡轉圈圈,所以k
的值就是環長度的「整數倍」。
假設相遇點距環的起點的距離為m
,那麼結合上圖的slow
指標,環的起點距頭結點head
的距離為k - m
,也就是說如果從head
前進k - m
步就能到達環起點。
巧的是,如果從相遇點繼續前進k - m
步,也恰好到達環起點。因為結合上圖的fast
指標,從相遇點開始走k步可以轉回到相遇點,那走k - m
步肯定就走到環起點了:
所以,只要我們把快慢指標中的任乙個重新指向head
,然後兩個指標同速前進,k - m
步後一定會相遇,相遇之處就是環的起點了。
力扣第 160 題「 相交鍊錶」
我的**:
class solution
return a;}};
思路:
本題書中思路比較清晰,無需總結
給你輸入兩個鍊錶的頭結點heada
和headb
,這兩個鍊錶可能存在相交。
如果相交,你的演算法應該返回相交的那個節點;如果沒相交,則返回 null。
比如題目給我們舉的例子,如果輸入的兩個鍊錶如下圖:
那麼我們的演算法應該返回c1
這個節點。
這個題直接的想法可能是用hashset
記錄乙個鍊錶的所有節點,然後和另一條鍊錶對比,但這就需要額外的空間。
如果不用額外的空間,只使用兩個指標,你如何做呢?
難點在於,由於兩條鍊錶的長度可能不同,兩條鍊錶之間的節點無法對應:
如果用兩個指標p1
和p2
分別在兩條鍊錶上前進,並不能同時走到公共節點,也就無法得到相交節點c1
。
解決這個問題的關鍵是,通過某些方式,讓p1
和p2
能夠同時到達相交節點c1
。
所以,我們可以讓p1
遍歷完鍊錶a
之後開始遍歷鍊錶b
,讓p2
遍歷完鍊錶b
之後開始遍歷鍊錶a
,這樣相當於「邏輯上」兩條鍊錶接在了一起。
如果這樣進行拼接,就可以讓p1
和p2
同時進入公共部分,也就是同時到達相交節點c1
:
那你可能會問,如果說兩個鍊錶沒有相交點,是否能夠正確的返回 null 呢?
這個邏輯可以覆蓋這種情況的,相當於c1
節點是 null 空指標嘛,可以正確返回 null。
按照這個思路,可以寫出如下**:
listnode getintersectionnode(listnode heada, listnode headb)
return p1;
}
這樣,這道題就解決了,空間複雜度為o(1)
,時間複雜度為o(n)
。 鍊錶題目一道
原題鏈結 題意很簡單。給定乙個單鏈表,反轉這個單鏈表,返回翻轉後的頭節點。要將鍊錶翻轉,很容易想到借助棧的後進先出的性質來改變鍊錶的順序。將鍊錶節點順序壓入棧中,鍊錶節點全部進棧以後,取棧頂元素作為新鍊錶的頭節點,然後將元素不斷出棧,每齣棧乙個元素就連線到新鍊錶的末尾。時間複雜度 將鍊錶元素壓入棧中...
另一道鍊錶題目
有乙個鍊錶,它有next以及child屬性,每乙個child或者next指向的node也有相同的屬性,現在問如何遍歷所有的node。演算法有幾種option,第一種是用額外儲存空間,另一種是no extra memory。昨天和同事討論了一下,發現這道題目其實可以用遞迴來做,非常容易,幾句話就寫好了...
分隔鍊錶 雙指標操作
給定乙個鍊錶和乙個特定值 x,對鍊錶進行分隔,使得所有小於 x 的節點都在大於或等於 x 的節點之前。你應當保留兩個分割槽中每個節點的初始相對位置。輸入示例 head 1 4 3 2 5 2,x 3 輸出示例 1 2 2 4 3 5 c 結構體 definition for singly linke...