概述
起因:leetcode題目 25. K 個一組翻轉連結串列
問題描述
給你連結串列的頭節點 head ,每 k 個節點一組進行翻轉,請你返回修改後的連結串列。
k 是一個正整數,它的值小於或等於連結串列的長度。如果節點總數不是 k 的整數倍,那麼請將最後剩餘的節點保持原有順序。
你不能只是單純的改變節點內部的值,而是需要實際進行節點交換。
示例一:
輸入:head = [1,2,3,4,5], k = 2
輸出:[2,1,4,3,5]
示例 2:
輸入:head = [1,2,3,4,5], k = 3
輸出:[3,2,1,4,5]
解決方法
我們需要構建一個函式,它會對連結串列進行K個節點翻轉。而不斷使用這個函式,就可以對每K個節點進行翻轉。
點選檢視程式碼
struct Res{
ListNode *head;
bool flag;
ListNode *tail;
};
Res reverse(ListNode* head,int k){
ListNode newHead;
ListNode *subHead,*subTail,*cur,*temp;
//subHead 記錄反轉過程的頭節點
//subTail 記錄反轉過程的尾節點
//cur 要反轉的節點
//temp 用於反轉的中間變數
int cnt = 0; //記錄長度
if(head){
subHead = head;
subTail = head;
cur = head->next;
cnt++;
}
while(cur && cnt<k){
temp = cur;
cur = cur->next;
subTail->next = temp->next;
temp->next = subHead;
subHead = temp;
cnt++;
}
bool flag = true;
if(cnt<k) flag = false;
return {subHead,flag,subTail};
}
函式邏輯
-
一開始翻轉連結串列的
head
和tail
都是正常連結串列的頭節點,cur
則是要進行翻轉的節點- 我們把
cur
作為新的head
,即舊的head
會成為cur
的下一個節點。 cnt
進行自增加一
- 我們把
-
重複這個過程,直到
cur
為空。 -
然後判斷
cnt
與K
的關係:cnt
<K
的話,則未能反轉K
個節點。flag
為 False。
注意:這個過程中
tail
不需要變化,因為一開始的正常連結串列頭節點就是翻轉後的尾節點。
其中,函式返回翻轉後的頭節點和尾節點。特別地,flag是判斷是否翻轉了K個數。
實現不滿足K個節點則不翻轉
當不滿足K個節點時,函式返回的 res
中的flag
屬性會為False。
這時對這個翻轉後的連結串列再次進行翻轉的話,就可以實現不翻轉。
主函式實現
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode *newHead,*subTail;
//首先進行一次翻轉,並初始newHead和subTail
auto res = reverse(head,k);
newHead = res.head;
subTail = res.tail;
//如果第一次翻轉就不滿足K個節點,再次進行翻轉,並返回新的newHead
if(res.flag == false){
res = reverse(newHead,k);
newHead = res.head;
subTail = res.tail;
return newHead;
}
//對每K個節點進行翻轉
while(1){
auto res = reverse(subTail->next,k);
//不滿足K個節點,再次翻轉,並直接返回結果。
if(res.flag == false){
res = reverse(res.head,k);
return newHead;
}
// 對subTail進行更新:連結翻轉後的子連結串列,並把subTail更新為子連結串列的tail。
subTail->next = res.head;
subTail = res.tail;
cout<<subTail->val<<endl;
}
return newHead;
}