给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
示例1:
输入: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]
1. 头插法
思路: 将链表根据 k 的值进行分组, 再分别对每一组进行反转。

代码实现:
/**
* 头插法
*
* @param head
* @param k
* @return
*/
public static ListNode reverseKGroup2(ListNode head, int k) {
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
ListNode curr = head;
// 计算链表长度
int len = 0;
while (curr != null) {
len++;
curr = curr.next;
}
// 根据 k的值进行分组
int n = len / k;
ListNode pre = dummyNode;
curr = head;
// 分组进行反转
for (int i = 0; i < n; i++) {
for (int j = 0; j < k - 1; j++) {
ListNode next = curr.next;
curr.next = curr.next.next;
next.next = pre.next;
pre.next = next;
}
// 准备进入下一组反转
pre = curr;
curr = curr.next;
}
return dummyNode.next;
}
2. 穿针引线法
思路: 将链表分组处理, 将其分为已经反转、正在反转、未反转三个部分。遍历链表, 根据 k 的值找到四个关键位置, 分别代表已经反转部分的尾结点、正在反转部分的头节点、正在反转部分的尾结点以及未反转部分的头节点, 使用变量 pre、start、end和next标记。

对待反转的部分进行反转:

调整指针位置, 进行下一组反转:

代码实现:
/**
* 穿针引线法
*
* @param head
* @param k
* @return
*/
public static ListNode reverseKGroup(ListNode head, int k) {
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
ListNode pre = dummyNode;
ListNode end = dummyNode;
while (end.next != null) {
// 先找到待反转链表部分的尾节点
for (int i = 0; i < k && end != null; i++) {
end = end.next;
}
if (end == null) {
// 当最后一组待反转链表长度小于k, 不满足要求时, 退出循环
break;
}
// 待反转链表部分的头节点
ListNode start = pre.next;
// 未反转 (下一组) 部分链表头节点
ListNode next = end.next;
end.next = null;
pre.next = reverse(start);
start.next = next;
pre = start;
end = pre;
}
return dummyNode.next;
}
private static ListNode reverse(ListNode head) {
ListNode pre = null;
ListNode curr = head;
while (curr != null) {
ListNode next = curr.next;
curr.next = pre;
pre = curr;
curr = next;
}
return pre;
}


1304

被折叠的 条评论
为什么被折叠?



