92. 反轉連結串列 II(C++)
阿新 • • 發佈:2022-03-09
目錄
連上原連結串列的頭結點,以此來規範頭節點變動和其他節點變動的程式碼,進行格式統一。
題目
給你單鏈表的頭指標 head
和兩個整數 left
和 right
,其中 left
<= right
。請你反轉從位置 left
到位置 right
的連結串列節點,返回 反轉後的連結串列 。
示例 1:
輸入:head = [1,2,3,4,5], left = 2, right = 4
輸出:[1,4,3,2,5]
示例 2:
輸入:head = [5], left = 1, right = 1
輸出:[5]
提示:
- 連結串列中節點數目為 n
- 1 <= n <= 500
- -500 <= Node.val <= 500
題解
對於連結串列的問題,一般都是要建一個 dummy node
以題目中的例子來說,變換的是 2,3,4 這三個點,我們需要找到第一個開始變換結點的前一個結點,只要讓 pre 向後走 m-1 步即可,用 pre 指向它。由於一次只能交換兩個結點,所以我們按如下的交換順序:
1 -> 2 -> 3 -> 4 -> 5 -> NULL 1 -> 3 -> 2 -> 4 -> 5 -> NULL // 第一次變換將結點 3 放到結點 1 的後面 1 -> 4 -> 3 -> 2 -> 5 -> NULL // 第二次變換將結點 4 放到結點 1 的後面
可以看出來,總共需要 right-left
步即可,因為每次變換都是規律的操作,就以第一次變換進行舉例。剛開始,pre
指向結點 1,cur
指向結點 2,然後我們建立一個臨時的結點 tmp
,用臨時變數儲存某個結點就是為了首先斷開該結點和前面結點之間的聯絡,這可以當作一個規律記下來。
每一次節點交換分為以下三個步驟:
-
第一步斷開結點 2 和結點 3,將結點 2 的 next 連到結點 4 上:
cur->next = t->next
-
第二步將結點 3 連到結點2的前面,即
t->next = pre->next
-
第三步將結點 1 連到結點 3,即
pre->next = tmp
這裡跟常見的連結串列反轉最大的區別在於以前prev、cur會向隨著連結串列遍歷反轉逐漸向後移動,這裡的prev、cur其實指向並沒有改變。即這裡的prev一直是1, cur一直是2, 是cur->next一直在變化。
完整程式碼如下:
/**
* 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:
ListNode* reverseBetween(ListNode* head, int left, int right) {
// 設定頭節點,來規範化頭節點反轉的特殊情況
ListNode* dummy = new ListNode(-1);
dummy->next = head;
ListNode* pre = dummy;
// left-1是為了找到開始變換節點的前一節點
for (int i = 0; i < left - 1; i++)
pre = pre->next;
// 本題中pre和cur不會變動!!
ListNode* cur = pre->next;
for (int i = left ; i < right; i++) {
ListNode* tmp = cur->next;
// 首先斷開臨時節點和前面節點的關係
cur->next = tmp->next;
tmp->next = pre->next;
pre->next = tmp;
}
return dummy->next;
}
};