算法設計與分析 第十二週
k個一組翻轉鏈表
1 題目描述
2 選題原因
講道理這個周確實沒講啥東西…秉承着隨機的原則,在首頁閉着眼睛點了一下鼠標,選中了這道題。
3 題目分析及算法
3.1 常規分析
分析這道題目,其實是比較簡單的。涉及的操作無非就是節點的轉移,思考清楚就沒有太大的難度。
看這道題,說白了就是將不同段的節點顛倒過來,其實實現起來很簡單。我們先看一段鏈表的倒置
。
當我們要倒置的時候,應該是從頭節點開始,依次將頭節點放在最後。例如上圖,我們從
1
開始,先使用一個指針指向2
,接着將1
節點放在隊列的最後(該節點下一個節點稍後會說),接着,將頭節點更新爲指針指向的節點(即節點2
)。
算法如下:
FOR i = 1: k
temp = head -> next;
head -> next = tail;
tail = head;
ENDFOR
3.2 問題所在
接下來,我們要考慮的問題是:先調換前面的組還是先調換後面的組。
仔細觀察一下。當前組的首節點會被放在最後,和下一個組的首節點相接,而下一組的首節點是什麼?取決於我們的調換順序。如果我們從前往後調換,那麼這一組會在下一組首節點被放在最後之前連接上!而如果我們從後往前調換,就會在下一組調換完成連接上節點,也正是正常順序!
4 關鍵代碼
4.1 組內節點調換
//反轉節點
while (count > 0) {
//next 下一個頭節點
//next_head 下一個要放在最後的節點
ListNode* next = head->next;
head->next = next_head;
next_head = head;
head = next;
count--;
}
4.2 遞歸的從後向前調換
while (next_head != NULL && count != k) {
next_head = next_head->next;
count++;
}
//遞歸後面的組先反轉,用反轉後新的頭作爲自己尾節點的下一個節點
if (count == k) {
next_head = reverseKGroup(next_head, k);
}
5 運行結果
6 源代碼
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* next_head = head; //標記下一組要反轉的位置
int count = 0; //標記當前組的節點數
//找到下一組節點
while (next_head != NULL && count != k) {
next_head = next_head->next;
count++;
}
//遞歸後面的組先反轉,用反轉後新的頭作爲自己尾節點的下一個節點
if (count == k) {
next_head = reverseKGroup(next_head, k);
//反轉節點
while (count > 0) {
//next 下一個頭節點
//next_head 下一個要放在最後的節點
ListNode* next = head->next;
head->next = next_head;
next_head = head;
head = next;
count--;
}
//指向新的頭
head = next_head;
}
return head;
}
};