[25. K 个一组翻转链表]
难度 困难
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明:
- 你的算法只能使用常数的额外空间。
- 你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group
解法一:
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode ans = new ListNode(-1);
ans.next = head;
ListNode start = head; //一组待翻转节点的起点
ListNode end = head; //一组待翻转节点的终点
ListNode pre = ans; //指向已翻转序列的终点,用来连接已翻转序列和未翻转序列
while(start != null) {
end = start;
//使 end 指向新一组待翻转节点的终点
for(int j = 1; j < k && end != null; j++) {
end = end.next;
}
//该组节点不足 k 个,剩余的节点保持原有顺序
if(end == null) {
return ans.next;
}
pre.next = end; //连接已翻转序列和未翻转序列
pre = start; //更新已翻转序列的尾部(因为该组的起始节点经过翻转后变为末端节点, 因此 start 的位置变为翻转后序列的终点)
ListNode startNext = end.next; //下一组待翻转的起点
//翻转该组节点(依次将start 所指的节点添加到end节点的后面)
//例如:end节点指向 3, start依次指向1 ,2
//'1'——>2——>3 '2'——>3——>1 3——>2——>1
for(int j = 1; j < k; j++) {
ListNode temp = start.next; //下一个要翻转的节点
start.next = end.next;
end.next = start;
start = temp;
}
start = startNext;
}
return ans.next;
}
}
解法二:递归
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if (head == null || k == 1) {
return head;
}
ListNode start = head, end = head;
ListNode remain = null; //指向剩余未翻转序列的起点
for (int i = 1; i < k && end != null; i++) {
end = end.next;
}
//该组节点不足 k 个,剩余的节点保持原有顺序
if(end == null) return head;
remain = end.next;
end.next = null;
head = reverseList(head); //翻转一组节点
start.next = reverseKGroup(remain, k); //连接剩余该组节点后的节点
return head;
}
private ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode prev = null; //已翻转序列的头结点
ListNode current = head; //当前需要翻转的节点
//采用头插法进行翻转
while (current != null) {
ListNode next = current.next;
current.next = prev;
prev = current;
current = next;
}
return prev;
}
}