本文正在参加「Java主题月 - Java 刷题打卡」,详情查看 活动链接
题目描述
K 个一组翻转链表
给你一个链表,每 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]
提示
- 列表中节点的数量在范围
sz内 1 <= sz <= 50000 <= Node.val <= 10001 <= k <= sz
思路分析
一开始解答这道题的时候,我试图对每 k 个进行反转,记录下 k+1 的指针,但是我们没有对 k.next 置为 null,这样在反转的时候处理很是复杂,后面看了一些优秀的解法,及时对 k.next 置为 null,最后再进行衔接,一下子方便很多了。
代码展示
链表的反转是个必须掌握的点,反转 k 个节点的时间复杂度是,空间复杂度是。
public ListNode reverseKGroup(ListNode head, int k) { //1,2 ,3,4, 5
ListNode dummy = new ListNode();
dummy.next = head;
ListNode start = dummy;
ListNode end = dummy;
while (end.next != null) { //end != null 会再走一下,到下面进行break
for (int i = 0; i < k; i++) {
if (end != null) {
end = end.next;
}
}
if (end == null){
break;
}
//下一组的头部
ListNode next = end.next; //3 5
end.next = null;
//现在的头部
ListNode currentHead = start.next; //currentHead = 1 currentHead = 3
//反转后的头部,currentHead变尾部了
ListNode reverseHead = reverse(currentHead); //reverseHead = 2,currentHead = 1 reverseHead = 4,currentHead = 3
start.next = reverseHead; //start.next = 2 start.next = 4
currentHead.next = next; //currentHead.next = 3 currentHead.next = 5
start = currentHead; //start = 1
end = start; //end 也是要设置一下的,因为 end 原本指向某个地址,但是反转了,这个地址变到前面了
}
return dummy.next;
}
//链表反转
private ListNode reverse(ListNode head){
ListNode prev = null;
ListNode current = head;
while (current != null){
ListNode next = current.next;
current.next = prev;
prev = current;
current = next;
}
return prev;
}
总结
像这样的 k 个一组翻转链表,虽然题意简单,但是真正实现是比较复杂的,很考验编程着对链表的掌握程度。如果按照上面逻辑一步步自己写出来,思路还是比较清晰的,也就是 k 个 k个 进行反转,每 k 个进行反转的时候,把 k+1 的指针保存下来,对 k.next 置为空,处理好衔接。