25.K 個一組翻轉鏈表
難度困難416
給你一個鏈表,每 *k *個節點一組進行翻轉,請你返回翻轉後的鏈表。
*k *是一個正整數,它的值小於或等於鏈表的長度。
如果節點總數不是 *k *的整數倍,那麼請將最後剩餘的節點保持原有順序。
示例:
給你這個鏈表:1->2->3->4->5
當 *k *= 2 時,應當返回: 2->1->4->3->5
當 *k *= 3 時,應當返回: 3->2->1->4->5
說明:
- 你的算法只能使用常數的額外空間。
- 你不能只是單純的改變節點內部的值,而是需要實際進行節點交換。
/***
* 迭代法
* 1.鏈表分區已翻轉 + 待翻轉 + 未翻轉部分
* 2.翻轉前確定翻轉的範圍 通過k來決定
* 3.記錄鏈表前驅和後繼 方便翻轉完成後,把已翻轉和未翻轉連接起來。
* 4.初始化兩個邊路pre end pre >代表待翻轉鏈表的前驅,end代表待翻轉的末尾。
* 5.經過k次 end到達鏈表末尾。 記錄待翻轉鏈表的後繼 next = end.next
* 6.翻轉鏈表,將三部分連接起來,然後重置pre 和 end 指針 進入下一個循環
* 7.特殊情況 翻轉部分長度不足k時,在定位end 完成後,end = null 已經到達末尾。
* 8.時間複雜度爲 O(n*K) 最好的情況爲 O(n) 最差的情況未 O(n^2)
* 9.空間複雜度爲 O(1)
* @param head
* @param k
* @return
*/
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dumy = new ListNode(0);
dumy.next = head;
ListNode pre = dumy;
ListNode end = dumy;
while (end.next != null) {
//確定待翻轉的範圍
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);
start.next = next;
pre = start;
end = pre;
}
return dumy.next;
}
public static ListNode reverse(ListNode head) {
ListNode pre = null;
ListNode curr = head;
//假設 1 -> 2 -> 3
while (curr != null) {
ListNode next = curr.next; // next = 2 // next = 3
curr.next = pre;// 1.next = null // 3.next = 1
pre = curr;// pre = 1; // 1 = 3
curr = next; // curr = 2 // 3 = null
}
return pre; //
}