--- tags: leetcode --- # [143. Reorder List](https://leetcode.com/problems/reorder-list/) --- # My Solution ## The Key Idea for Solving This Coding Question 如何以交叉編織的方式合併兩個單向鏈結串列 (第 38 ~ 53 行) 1. 假設 `head` 指向的單向鏈結串列長度==小於或等於== `head2` 指向的單向鏈結串列。 2. 因為 `it1->next` 與 `it2->next` 皆必須改變所要指向的節點,所以先分別以 `tmp1` 與 `tmp2` 紀錄 `it1->next` 與 `it2->next` 目前所指向的節點。 3. 依題意將 `it1->next` 與 `it2->next` 指向應指向的節點。 * `it1->next` 指向 `it2`。 * `it1` 走到 `tmp1` 所在節點 (也就是 `it1->next` 原本指向的節點)。 * 因為 `head` 指向的單向鏈結串列長度小於或等於 `head2` 指向的單向鏈結串列,所以要先檢查 `it1` 是否為 `nullptr` 。若 `it1` 為 `nullptr` ,表示合併結束,離開 `while` 迴圈。否則,繼續合併。 * `it2->next` 指向 `it1` 。 * `it2` 走到 `tmp2` 所在節點 (也就是 `it2->next` 原本指向的節點)。 4. 重複步驟 2 與 3 。 ## C++ Code ```cpp= /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: void reorderList(ListNode *head) { if (head == nullptr || head->next == nullptr) { return; } ListNode *preSlow = nullptr, *slow = head, *fast = head; while (fast != nullptr && fast->next != nullptr) { preSlow = slow; slow = slow->next; fast = fast->next->next; } // Break the list. preSlow->next = nullptr; // Reverse the second half of the list. ListNode *head2 = nullptr; while (slow != nullptr) { ListNode *tmp = slow->next; slow->next = head2; head2 = slow; slow = tmp; } // Interweave the two lists. ListNode *it1 = head, *it2 = head2; while (true) { ListNode *tmp1 = it1->next; ListNode *tmp2 = it2->next; it1->next = it2; it1 = tmp1; if (it1 == nullptr) { // Because the list length of it1 is shorter // than or equal to that of it2, it1 reaches // the end of its list first. break; } it2->next = it1; it2 = tmp2; } } }; ``` ## Time Complexity $O(n)$ $n$ is the total number of nodes in the linked list. ## Space Complexity $O(1)$ # Miscellaneous <!-- # Test Cases ``` [1,2,3,4] ``` ``` [1,2,3,4,5] ``` ``` [1] ``` ``` [1,2] ``` ``` [1,2,3] ``` -->