leetcode 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 206.反转链表
- 定义一个 dummyHead,令 prev=dummyHead 表示已反转的最后一个节点,用于连接反转后的链表
- 遍历链表分组:k 个一组(不够 k 个直接返回)
- 为了防止走丢,还是一样的保存一下分组的尾结点 tail 的下一个节点 tailNext;
- 反转这一组链表:需要得到反转之后的头尾结点,可以用数组保存;
- 得到反转之后的头尾进行连接:
(1)头部连接在 prev 后面,prev.next=head;
(2)尾部连接在 tailNext 前面,tail.next=tailNext;- 更新信息进行下一次的反转和连接:
(1)prev=tail;
(2)head=tail.next;- 直到剩余个数不足 k 个或者全部反转完结束。
public class Solution25 {
/**
* Definition for singly-linked list
*/
class ListNode {
int val;
ListNode next;
public ListNode(int val) {
this.val = val;
}
}
/**
* 1.定义 dummyHead 用于连接, 不然第一组无法连接
* 2.使用 prev 指向反转部分的前一个结点,tail 每次从待反转部分的前一个开始 k 个一组进行遍历分割, 如果剩余的长度不足以组就直接返回;
* 3.保存 tailNext=tail.next 用于反转以后的连接;
* 4.调用方法反转链表并得到反转以后的头尾结点;
* 5.将反转以后的链表连接在原链表之中:
* prev.next = head;
* tail.next = tailNext;
* 6.初始化下次的值:
* prev = tail;
* head = tail.next;
*/
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode prev = dummyHead;
while (head != null) {
ListNode tail = prev;
// 分组
for (int i = 0; i < k; i++) {
tail = tail.next;
// 剩余节点个数不够一组
if (tail == null) {
return dummyHead.next;
}
}
// 保存下一组的起始位置
ListNode tailNext = tail.next;
// 反转链表——保存反转后链表的头尾结点
ListNode[] result = reverseList(head, tail);
head = result[0];
tail = result[1];
// 连接
// 反转以后原来的尾成为了头连接在 prev 后面, 原来的头成为了尾连接在 tailNext 前面
prev.next = head;
tail.next = tailNext;
// 下次开始初始值
prev = tail;
head = tail.next;
}
return dummyHead.next;
}
/**
* 反转给定的一段链表, 将反转以后的头尾返回.
*/
public ListNode[] reverseList(ListNode head, ListNode tail) {
ListNode tailNext = tail.next;
ListNode cur = head;
ListNode prev = null;
while (cur != tailNext) {
ListNode curNext = cur.next;
cur.next = prev;
prev = cur;
cur = curNext;
}
return new ListNode[]{tail, head};
}
}
也可以直接进行反转:
1.计算长度进行分组;定义傀儡头节点便于反转连接
2.对每组进行反转:使用 cur 遍历组内节点,将组内每一个节点插入到 傀儡头结点指针 prev 和head之间实现反转;
3.初始化下次的反转指针:prev 指向反转之后组内最后一个节点(就是 cur),cur还是指向未遍历节点(prev.next);
public class Solution25 {
/**
* Definition for singly-linked list
*/
class ListNode {
int val;
ListNode next;
public ListNode(int val) {
this.val = val;
}
}
/**
* 1.计算链表长度
* 2.将链表分成 k 组,每组反转
* 3.反转完成继续分组重复上一步
*/
public ListNode reverseKGroup(ListNode head, int k) {
if (head == null) return null;
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode cur = head;
int length = 0;// 链表的长度
while (cur != null) {
cur = cur.next;
length++;
}
cur = head;
ListNode prev = dummyHead;
ListNode curNext = null;
// 分成 k 组
// 每组进行反转: 遍历组内的每个节点, 将其插入到 prev 和 head 之间实现反转
for (int i = 0; i < length / k; i++) {
for (int j = 0; j < k-1; j++) {
// 反转
curNext = cur.next;
cur.next = curNext.next;
curNext.next = prev.next;
prev.next = curNext;
}
// 下一次反转初始值
prev = cur;
cur = prev.next;
}
return dummyHead.next;
}
}
-----------------------------------------------------------------------------有始有终分割线----------------------------------------------------------------------------------