Linked List 的反轉操作– 陪你刷題
文章推薦指數: 80 %
在做linked list 相關題目時,不論是recursive 還是iterative 寫法,寫起來都相當燒腦,因此決定以自己好理解的方式,整理一篇跟linked list 反轉操作 ...
跳至主要內容
在做linkedlist相關題目時,不論是recursive還是iterative寫法,寫起來都相當燒腦,因此決定以自己好理解的方式,整理一篇跟linkedlist反轉操作的文章,作為往後複習來用。
Leetcode#206ReverseLinkedList
遞迴寫法
在開始透過遞迴的方式來反轉linkedlist之前,先回想如何才能使用遞迴,使用遞迴需要滿足以下3個條件:
一個問題的解可以分為幾個子問題的解
這個問題和其子問題除了數據規模不同,求解思路完全一樣
存在遞迴終止條件(basecase)
在思考遞迴問題時,很重要的一點是,絕對不要在腦中想把遞迴一層一層的想清楚,這不符合一般人腦的思考方式!
單純聚焦於反轉過程中的某一子問題,可以幫助我們思考清楚整個遞迴,如下圖,如果反轉完head→next,接著該怎麼反轉head呢?
第一步將head→next接往head做到反轉:
head->next->next=head;
第二步將head→next指到NULL,至此head節點的前後都被正確反轉。
head->next=NULL;
遞迴問題中,必須定義出終止條件,以反轉linkedlist來說,當走到最後一個節點時後,該節點就不需要再往後處理,而這個節點就會是新的head節點,應該將新頭節點回傳。
掌握以上要點後,遞迴的程式碼也就可以輕鬆寫出。
ListNode*reverseList(ListNode*head)
{
if(head->next==nullptr)
returnhead;
ListNode*new_head=reverseList(head->next);
head->next->next=head;
head->next=NULL;
returnnew_head;
}
非遞迴寫法
專注於當前節點的反轉即可。
因為反轉操作而喪失連結的節點,需要儲存起來。
classSolution{
public:
ListNode*reverseList(ListNode*head){
if(head==nullptr)
returnNULL;
ListNode*prev=nullptr,*nxt;
while(head!=nullptr)
{
nxt=head->next;
head->next=prev;
prev=head;
head=nxt;
}
returnprev;
}
};
Leetcode#92ReverseLinkedListII
此題的input給你[m,n]的區間,要你reverse特定區間內的節點,以下分為遞迴與非遞迴的寫法。
遞迴寫法
我們先從如何reverse前N個節點開始了解。
Reverse前N個節點
與reverse整個linkedlist差別在於:
必須將反轉過後的linkedlist的尾節點(圖中的new_tail或反轉前的head)接往第N+1個節點(圖中的successor或者你要說它是反轉區間最後節點的下一個節點),之前reverse整個linkedlist時候,會將當前的節點的next指向NULL,但這個case下要將當前節點指向第N+1的節點。
遞迴的basecase為當n=1的時候,代表不必再反轉後續節點,但是要將第N+1個節點紀錄下來,並且回傳新的頭節點。
ListNode*successor=nullptr;
ListNode*reverseN(ListNode*head,intn)
{
if(n==1)
{
successor=head->next;
returnhead;
}
ListNode*new_head=reverseN(head->next,n-1);
head->next->next=head;
head->next=successor;
returnnew_head;
}
反轉特定區間節點
知道如何reverse前N個節點後,其實reverse區間[m,n]的節點,等同於我們先前進到第m個節點,就以第m個節點開始來reversen-m個節點即可。
透過遞迴來實作的話,遞迴的basecase即為m=1的時候,回傳反轉後的新頭節點,其他的case下直接將節點一個一個走下去,更新區間的開頭與結束index即可。
ListNode*reverseBetween(ListNode*head,intm,intn)
{
if(m==1)
{
returnreverseN(head->next,n);
}
head->next=reverseBetween(head->next,m-1,n-1);
returnhead;
}
非遞迴寫法
相比於遞迴寫法,非遞迴更加複雜。
以下圖為例,可以觀察到兩個現象:
反轉區間的前一個節點永遠接往新的頭節點(圖中的new_head)
反轉過後的linkedlist的尾節點(圖中的new_tail)接往反轉區間的後一個節點
只要在每次反轉時把握兩個現象正確,再搭配反轉動作,就可以正確完成反轉區間的任務。
總結一下,每次反轉都會做到以下三樣任務:
反轉區間的前一個節點永遠接往新的頭節點(圖中的new_head)
反轉過後的linkedlist的尾節點(圖中的new_tail)接往反轉區間的後一個節點
反轉兩個節點
另外提一下,這邊使用哨兵節點來處理會更好,可以避免需要特別處理m=1時的特殊狀況。
classSolution{
public:
ListNode*reverseBetween(ListNode*head,intm,intn){
ListNode*dummy=newListNode(0),*pre=dummy;
dummy->next=head;
for(inti=0;i
classSolution{
public:
ListNode*reverseBetween(ListNode*head,intm,intn){
if(head==nullptr||head->next==nullptr)
returnhead;
if(m==n)
returnhead;
ListNode*dummy=newListNode(0),*prev=dummy;
dummy->next=head;
for(inti=1;i
遞迴寫法
這題可以視為#92的進階題。
每次都先走k步確認有足夠多的數量可以進行反轉。
進行反轉後需要將新的head節點回傳回去,以利接起整個linkedlist。
classSolution{
public:
ListNode*reverseKGroup(ListNode*head,intk){
if(k==1)
returnhead;
ListNode*walker=head;
for(inti=0;i
透過forloop依序swap每個group,已經知道list的總長度,就可以控制總共要swap多少個group。
延伸練習
Leetcode#234,#143
結論
在處理linkedlist問題時,最重要一點就是不要讓任何節點變成孤兒,了解題目後,把題目需要的操作列出來,確認都有執行且執行過程不會讓任何節點變為孤兒,那就可以放心透過遞迴或是iterative的模式操作。
Updatedon2021-05-3010:38:24星期日
文章導覽
上一篇文章上一篇文章:TopKelement–陪你刷題下一篇文章下一篇文章:CS:APP學習筆記
followme
linkedin
github
近期文章
MaximumSubarraySum問題–陪你刷題
設計一個hashtable–陪你刷題
Leetcode#29DivideTwoIntegers–陪你刷題
Leetcode#647PalindromicSubstrings–陪你刷題
Leetcode#329LongestIncreasingPathinaMatrix–陪你刷題
分類
CS:APP
Leetcode
linuxkernel
程式設計
自我成長
站內文章搜尋
搜尋關鍵字:
搜尋
彙整
2022年6月 (3)
2022年5月 (6)
2022年1月 (2)
2021年11月 (1)
2021年10月 (2)
2021年9月 (1)
2021年8月 (1)
2021年4月 (2)
2021年3月 (1)
2021年2月 (3)
2021年1月 (5)
2020年12月 (8)
2020年11月 (3)
2020年10月 (1)
2020年9月 (5)
2020年6月 (1)
2019年12月 (1)
2019年10月 (1)
2019年9月 (1)
2019年7月 (1)
2019年6月 (1)
近期文章
MaximumSubarraySum問題–陪你刷題
設計一個hashtable–陪你刷題
Leetcode#29DivideTwoIntegers–陪你刷題
Leetcode#647PalindromicSubstrings–陪你刷題
Leetcode#329LongestIncreasingPathinaMatrix–陪你刷題
分類
CS:APP
Leetcode
linuxkernel
程式設計
自我成長
近期留言「TopologicalSort–陪你刷題–haogroot'sBlog」於〈Backtracking回溯法–陪你刷題〉發佈留言「Leetcode#329LongestIncreasingPathinaMatrix–陪你刷題–haogroot'sBlog」於〈TopologicalSort–陪你刷題〉發佈留言彙整
2022年6月
2022年5月
2022年1月
2021年11月
2021年10月
2021年9月
2021年8月
2021年4月
2021年3月
2021年2月
2021年1月
2020年12月
2020年11月
2020年10月
2020年9月
2020年6月
2019年12月
2019年10月
2019年9月
2019年7月
2019年6月
延伸文章資訊
- 1LeetCode 解題筆記(Linked List類型題目) - HackMD
var mergeTwoLists = function(l1, l2) { // 儲存結果的ListNode var result = new ListNode(0); // 目前Node位置...
- 2[C 常見考題] Linked List Allocation Quiz - 程式扎記
[C 常見考題] Linked List Allocation Quiz · PL createLL2() · { · PL head = NULL; · printf("\t[Info] Cr...
- 3筆試面試題總結之單鏈表(Linked List) - 台部落
題目中一般涉及到的鏈表均爲單鏈表,因此總結的大部分操作也是以單鏈表爲主。 此總結爲刷完LeetCode中標籤爲Linked List的題之後寫的,所以涉及的操作和 ...
- 4linked list c面試的測驗範本和範例,1111、DCARD
提供c面試考題指標相關PTT/Dcard文章,想要了解更多有關健康/醫療文章或書籍, ... 萊禮- 透視C語言指標(之前有大略翻過,在面試時重新精讀) Leetcode的Linked List...
- 5聯發科c考題、鏈結串列題目在PTT/mobile01評價與討論
linked list c考題在PTT/mobile01評價與討論, 提供聯發科c考題、鏈結串列題目、單向鏈結串列c就來健身資訊懶人包,有最完整linked list c考題體驗分享 ...