题目
来源:LeetCode.
给你一个链表,每 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]
示例 3:
输入:head = [1,2,3,4,5], k = 1
输出:[1,2,3,4,5]
示例 4:
输入:head = [1], k = 1
输出:[1]
提示:
- 列表中节点的数量在范围 s z sz sz 内
- 1 < = s z < = 5000 1 <= sz <= 5000 1<=sz<=5000
- 0 < = N o d e . v a l < = 1000 0 <= Node.val <= 1000 0<=Node.val<=1000
- 1 < = k < = s z 1 <= k <= sz 1<=k<=sz
接下来看一下解题思路:
思路一:递归:
每次递归只需要考虑两件事:
- 组内的链表翻转
- 如何将每组翻转的结果串联起来
组内翻转,我们需要知道这次翻转的头部和尾部;
翻转后头部就变成尾部了,所以将头部head
指向下一次递归返回的结果;
这样就巧妙的将每组的结果串联起来了
public static ListNode reverseKGroup1(ListNode head, int k) {
if (head == null || head.next == null || k <= 1) {
return head;
}
// 当前组的尾结点
ListNode tail = head;
for (int i = 1; i < k && tail != null; ++i) {
tail = tail.next;
}
if (tail == null) {
return head;
}
// 下一组的头结点
ListNode next = tail.next;
// 翻转每个组内的结点
reverse(head, tail);
// 连接下一组的头结点
head.next = reverseKGroup(next, k);
return tail;
}
/**
* 单组链表翻转
* @param head
* @param tail
*/
private static void reverse(ListNode head, ListNode tail) {
if (head == tail) {
return;
}
reverse(head.next, tail);
head.next.next = head;
head.next = null;
}
思路二:迭代:
首先,需要计算链表的长度,用来判断需要翻转几次
对于链表的处理我们一般需要定义三个结点(前驱结点、当前结点、后继结点)
然后做一个大循环,判断有几组需要翻转;
再做一个循环,用于改变链表的指向,做组内翻转;
我们还需要定义一个结点,用于返回翻转后的结果链表;
public static ListNode reverseKGroup(ListNode head, int k) {
if (head == null || head.next == null || k <= 1) {
return head;
}
// 用于保存翻转后的链表头结点
ListNode node = new ListNode(-1, head);
// 计算链表的长度
int length = 0;
while (head != null) {
++length;
head = head.next;
}
head = node.next;
// 当前结点的后继结点
ListNode next = null;
// 当前结点
ListNode cur = head;
// 当前结点的前驱结点,用于连接翻转后的每一组
ListNode prev = node;
for (int i = 0; i < length / k; ++i) {
for (int j = 0; j < k - 1; ++j) {
next = cur.next;
cur.next = next.next;
next.next = prev.next;
prev.next = next;
}
prev = cur;
cur = prev.next;
}
return node.next;
}