題目25,24:
給你一個鏈表,每 k 個節點一組進行翻轉,請你返回翻轉後的鏈表。
k 是一個正整數,它的值小於或等於鏈表的長度。
如果節點總數不是 k 的整數倍,那麼請將最後剩餘的節點保持原有順序。
示例 :
給定這個鏈表:1->2->3->4->5
當 k = 2 時,應當返回: 2->1->4->3->5
當 k = 3 時,應當返回: 3->2->1->4->5
說明 :
你的算法只能使用常數的額外空間。
你不能只是單純的改變節點內部的值,而是需要實際的進行節點交換。
題解:
這個題在leetcode屬於困難型,對於這個題的解法可以這樣想:
首先,對一個鏈表的翻轉我們肯定很熟悉,那麼k個一組不就是翻轉k個鏈表嘛,不過是翻轉之前需要將未翻轉的標記一下next,翻轉了過後再將第一個鏈表的尾節點start.next = next,然後在循環進行下一個鏈表的翻轉,直接將翻轉封裝成一個方法reverse(ListNode start)。在翻轉的時候爲了讓頭節點也有前驅,我們自己定義一個headHead,如圖所示:
一次翻轉結束,更新pre end,start,end進行下一次翻轉,如果end爲到達指定的長度就結束了,說明節點數不夠了嘛,然後就不用翻轉了。整個操作空間複雜度O(1),常數額外空間,時間複雜度O(n*k),在題解中還看到一種優化說不用判斷最後一個鏈表的長度,直接翻轉就完了,如果最後發現長度不夠再翻轉回來,各位可以試試。
給出我的結果以及代碼:
public ListNode reverseKGroup(ListNode head, int k) {
//如果爲空,或者只有一個節點,直接返回嘛
if (head == null || head.next == null){
return head;
}
//給頭節點一個前驅,不用單獨爲頭節點考慮了
ListNode headHead = new ListNode(-1);
headHead.next = head;
ListNode pre = headHead;
ListNode end = headHead;
while (end.next != null){
//end移動到末尾
for (int i = 0; i <k&&end!=null ; i++) {
end = end.next;
}
if (end == null){
break;
}
ListNode start = pre.next;
ListNode next = end.next;
end.next = null;
//翻轉鏈表,將頭連接到上一個鏈表的末尾
pre.next = reverse(start);
//末尾要連接到下一個連接的next,
start.next = next;
pre = start;
end = start;
}
return headHead.next;
}
//翻轉鏈表
private ListNode reverse(ListNode start) {
if (start == null || start.next == null){
return start;
}
ListNode p = start;
ListNode q = start.next;
while (q != null){
ListNode t = q.next;
q.next = p;
p = q;
q = t;
}
start.next = null;
return p;
}```