--- title: "算法面試套路|原地反轉鏈表(In-place Reversal of Linked-List)" description: "Patterns for Coding Questions: Depth-First Search." image: https://i.imgur.com/Wnnr2qC.png author: Hsins tags: LeetCode, Coding Interview robots: breaks: GA: disqus: --- # 算法面試套路|原地反轉鏈表(In-place Reversal of Linked-List) <p style="text-align: center"> <img src="https://i.imgur.com/Wnnr2qC.png" height=200/> </p> > 本篇內容主要為 [Grokking the Coding Interview: Patterns for Coding Questions](https://www.educative.io/courses/grokking-the-coding-interview) 的翻譯與整理,行有餘力建議可以購買該專欄課程閱讀並在上面進行練習。 ## 重點整理 - 原地反轉鏈表(In-place Reversal of Linked-List) - 策略:使用現有的節點物件實例,而不使用額外的記憶體 - 題型: - 樹的逐層順序遍歷 - 樹的層級相關操作 ## 題目匯總 - `0025` Reverse Linked List II - `0092` Reverse Nodes in k-Group ## [例題] Reverse a Linked-List ### 問題 給定一個單向鏈結串列(singly linked-list)的頭節點,反轉此鏈結串列,撰寫一函數返回鏈結串列反轉後的頭節點。 **Example** <p style="text-align: center"> <img src="https://i.imgur.com/QBiNhuw.png" /> </p> ### 題解 為了反轉鏈結串列,我們需要每一次反轉一個節點。我們使用變數 `current` 在一開始指向鏈結串列的頭節點,並用變數 `previous` 指向遍歷過的節點,在最一開始他將指向 `null`。 在後續的步驟中,我們透過在向下一個節點前進之前,將當前節點 `current` 指向 `previous` 來反轉當前節點;同時,我們需要更新 `previous` 為剛處理過的節點。上述演算法如圖所示: <p style="text-align: center"> <img src="https://i.imgur.com/qhkwlsH.png"> <img src="https://i.imgur.com/9DKQqBf.png"> <img src="https://i.imgur.com/FgKmXKU.png"> <img src="https://i.imgur.com/lFGGKdK.png"> <img src="https://i.imgur.com/kf5C57h.png"> <img src="https://i.imgur.com/qibrGQs.png"> <img src="https://i.imgur.com/rwQQ3GX.png"> </p> ### 代碼 #### C++ ``` cpp class ReverseLinkedList { public: static ListNode *reverse(ListNode *head) { ListNode *curr = head; ListNode *prev = nullptr; ListNode *next = nullptr; while (curr != nullptr) { next = curr->next; curr->next = prev; prev = curr; curr = next; } return prev; } } ``` #### Java ``` java class ReverseLinkedList { public static ListNode reverse(ListNode head) { ListNode curr = head; ListNode prev = null; ListNode next = null; while (curr != null) { next = curr.next; curr.next = prev; prev = curr; curr = next; } return prev; } } ``` #### JavaScript ``` javascript const reverse = (head) => { let curr = head; let prev = null; let next = null; while (curr !== null) { next = curr.next; curr.next = prev; prev = curr; curr = next; } return prev; } ``` #### Python ``` python def reverse(head): prev, curr, next = None, head, None while curr is not None: next = curr.next curr.next = prev prev = curr curr = next return prev ``` ### 分析 - 時間複雜度:$\mathcal{O}(n)$,其中 $n$ 為鏈結串列中的節點總數 - 空間複雜度:$\mathcal{O}(1)$ ## [例題] Reverse a Sub-List ### 問題 給定一個鏈結串列(singly linked-list)與兩個位置 `p` 和 `q`,反轉鏈結串列中 `p` 至 `q` 之間的部分。 **Example** <p style="text-align: center"> <img src="https://i.imgur.com/WPVKFra.png" /> </p> ### 題解 這一題遵循 **原地反轉鏈表(In-place Reversal of Linked-List)** 策略,我們將使用與 [Reverse a Linked-List](#例題-Reverse-a-Linked-List) 相同的處理方式。步驟如下: 1. 省略前面 `p-1` 個結點,直到抵達位置 `p` 2. 保存第 `p-1` 個結點的位置,用來串起後續反轉部分鏈結串列 3. 使用 [Reverse a Linked-List](#例題-Reverse-a-Linked-List) 的解決方法翻轉 `p` 到 `q` 之間的鏈結串列 4. 將上述翻轉的部分與 `p-1` 和 `q+1` 連結 ### 代碼 #### C++ ``` cpp ``` #### Java ``` java class ReverseSubList { public static ListNode reverse(ListNode head, int p, int q) { if (p == q) return head; // skipping 'p-1' nodes, curr will point to 'p' node ListNode curr = head; ListNode prev = null; for (int i = 0; curr != null && i < p - 1; ++i) { prev = curr; curr = curr.next; } // focus three parts: [0, p-1] [p, q] [q+1, -1] ListNode lastNodeOfFirstPart = prev; ListNode lastNodeOfSubList = curr; ListNode next = null; for (int i = 0; curr != null && i < q - p + 1; ++i) { next = curr.next; curr.next = prev; prev = curr; curr = next; } // connect parts if (lastNodeOfFirstPart != null) lastNodeOfFirstPart.next = prev; else head = prev; lastNodeOfSubList.next = curr; return head; } } ``` #### JavaScript ``` javascript ``` #### Python ``` python ``` ### 分析 - 時間複雜度:$\mathcal{O}(n)$,其中 $n$ 為鏈結串列中的節點總數 - 空間複雜度:$\mathcal{O}(1)$ ## [例題] Reverse every K-element Sub-List ### 問題 ### 題解 ### 代碼 #### C++ ``` cpp ``` #### Java ``` java ``` #### JavaScript ``` javascript ``` #### Python ``` python ``` ### 分析 - 時間複雜度:$\mathcal{O}(n)$,其中 $n$ 為鏈結串列中的節點總數 - 空間複雜度:$\mathcal{O}(1)$ ## 參考資料 - [Coding Patterns: In-place Reversal of a Linked List | emre.me](https://emre.me/coding-patterns/in-place-reversal-of-a-linked-list/) - [Inplace Linked List Reversal Pattern | Astik Anand](https://astikanand.github.io/techblogs/coding-problem-patterns/inplace-linked-list-reversal-pattern)
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.