给你链表的头节点 head ,每 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]
在解决上述问题时,需要先了解一组链表的反转
一组链表反转
链表节点结构
public class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
解决方法:
一组链表反转从左往右依次更改当前的next节点为上一个,需要用一个临时节点存储当前节点的next节点,避免更改后找不到这个节点
在更改为上一个后,将pre节点设置为当前节点,cur设置为临时节点,临时节点在每次循环时赋值为cur节点的next节点
根据上述方法的描述,写出下列代码
// 反转链表
ListNode reverse(ListNode head) {
// pre指针用于记录当前节点的前一个节点,初始化为null
// cur指针用于遍历链表
ListNode pre = null;
ListNode cur = head;
// 当cur不为空时,继续反转
while(cur != null) {
// 保存cur的下一个节点
ListNode tmp = cur.next;
// 反转当前节点的指向
cur.next = pre;
// 移动pre和cur指针
pre = cur;
cur = tmp;
}
// 返回反转后的链表的头节点(原链表的尾节点)
return pre;
}
在了解一组链表的反转后再看k个一组链表反转
k个一组链表反转
解决方法:
方法一:反转既是先进后出的特点,使用栈来解决,栈中包含k个值的时候,依次弹出
方法二:分成多个一组链表反转,可以在空间复杂度为O(1)的情况下完成反转
初始需要两个变量
pre和cur,pre代表待翻转链表的前驱节点,cur代表待翻转链表的末尾节点经过k次循环,cur到达本次反转的末尾,记录待翻转链表的后继
使用两个遍历start和end,start代表待翻转链表的初始节点,end代表待翻转链表的后驱节点
cur的下一个节点设置为null,避免影响后续节点顺序,在对start节点进行反转,并返回反转后的头节点赋值给pre的下一个节点,start此时是反转后的末尾节点,设置下一个为end
将cur设置成end节点,pre设置成start节点
时间复杂度为 O(n∗K) 最好的情况为 O(n) 最差的情况未 O(n^2)
空间复杂度为 O(1) 除了几个必须的节点指针外,我们并没有占用其他空间
使用方法二来解决这个问题
方法二对应的代码如下
public ListNode reverseKGroup(ListNode head, int k) {
// 创建一个哑节点(dummy node),它的next指向链表的头节点
// 哑节点的作用是方便处理头节点被反转的情况
ListNode dum = new ListNode(0);
dum.next = head;
// pre指针用于记录每组反转链表的前一个节点
// cur指针用于遍历链表
ListNode pre = dum;
ListNode cur = dum;
// 当cur指针的下一个节点不为空时,继续遍历
while(cur.next != null) {
// 向前移动cur指针k步,检查接下来的k个节点是否存在
for(int i = 0; i < k && cur != null; i++) cur = cur.next;
// 如果cur为空,说明剩余节点不足k个,跳出循环
if (cur == null) break;
// 记录每组需要反转的链表的起始节点和结束节点的下一个节点
ListNode start = pre.next;
ListNode end = cur.next;
// 将cur的next置为null,切断与后续节点的连接,准备反转
cur.next = null;
// 反转start到end之间的链表,并更新pre.next指向反转后的链表头
pre.next = reverse(start);
// 将反转后的链表的尾节点指向原链表中下一组的头节点
start.next = end;
// 更新pre和cur指针,pre指向反转后的链表的尾节点,cur也指向这里
// 以便下一轮循环从新的位置开始
pre = start;
cur = start;
}
// 返回反转后的链表的头节点(哑节点的下一个节点)
return dum.next;
}
// 反转链表
ListNode reverse(ListNode head) {
// pre指针用于记录当前节点的前一个节点,初始化为null
// cur指针用于遍历链表
ListNode pre = null;
ListNode cur = head;
// 当cur不为空时,继续反转
while(cur != null) {
// 保存cur的下一个节点
ListNode tmp = cur.next;
// 反转当前节点的指向
cur.next = pre;
// 移动pre和cur指针
pre = cur;
cur = tmp;
}
// 返回反转后的链表的头节点(原链表的尾节点)
return pre;
}
至此题目完成
1302

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



