给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/reverse-nodes-in-k-group
分析:本题在力扣上标签是难题,可是本题并不难在思路,而是难在细节上。我们先来进行思路分析:
(1)所有这种链表类的让你操作节点做一些操作的,都一定要记得虚拟头指针这个小技巧,不管有没有用,先用上再说。遍历整个链表,当指针为空时,停止遍历。
(2) 在第一步的整个链表循环内,开始按照输入的k值进行分组,利用for循环,找到长度为k的子链表首尾节点。此时需要注意,有可能此时链表所剩余长度不够k,我们可以根据内存循环时长度值来判断,如果所剩余长度不够k,那么就不用翻转了,直接将剩余的这一段连接到上一段翻转后的头节点就行。
(3) 如果够,那就将首尾放入到反转函数中,开始翻转,并最终返回头指针。
其实本题思路就这些,但是里面的细节点很不好处理:
1、首先,头指针,如果没有头指针,你需要多判断很多中情况。
2、如何判断所剩链表长度够不够k,也就是说用不用翻转?就根据内层循环的结束条件判断,如果现在内存循环结束但是却没有遍历k次,很明显是不够了,那我们就直接将本次循环的第一个节点链接到上一次循环返回的最后一个节点上即可
3、我们每次内部循环后,都要记得将链表链接完整,否则就会造成链表不能正常找到下一个节点。
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode hair = new ListNode(0);
hair.next = head;
ListNode pre = hair;
while (head != null) {
ListNode tail = pre;
// 查看剩余部分长度是否大于等于 k
for (int i = 0; i < k; ++i) {
tail = tail.next;
if (tail == null) {
return hair.next;
}
}
ListNode nex = tail.next;
ListNode[] reverse = myReverse(head, tail);
head = reverse[0];
tail = reverse[1];
// 把子链表重新接回原链表
pre.next = head;
tail.next = nex;
pre = tail;
head = tail.next;
}
return hair.next;
}
public ListNode[] myReverse(ListNode head, ListNode tail) {
ListNode prev = tail.next;
ListNode p = head;
while (prev != tail) {
ListNode nex = p.next;
p.next = prev;
prev = p;
p = nex;
}
return new ListNode[]{tail, head};
}
}