笔记---K个一组链表反转(java)

题目:25. K 个一组翻转链表 - 力扣(LeetCode)

/**
 * Definition for singly-linked list.
 * 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; }
 * }
 */
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};
    }
}

比较难理解的是myReverse()部分

**reverseKGroup 方法**

这个方法接收两个参数,一个是 ListNode 类型的 head,代表链表的头结点;另一个是整数类型 k,表示我们要反转连续 k 个节点组成的子链表的数量。该方法返回反转后的链表头结点。

以下是 reverseKGroup 方法的详细步骤:

1. 创建一个新的虚拟头结点 hair,其 next 指针指向原链表的头结点 head。同时定义一个预置结点 pre,初始时也指向虚拟头结点 hair。

2. 使用 while 循环遍历链表,直到找到满足条件的子链表,或者遍历完整个链表。

3. 在 while 循环内,首先定义一个尾结点 tail,并使用 for 循环查看剩余部分长度是否大于等于 k。如果小于 k,则直接返回反转后的头结点。

4. 如果满足反转条件,则保存 tail 结点的后继结点 nex,并调用 myReverse 方法反转从 head 到 tail 的子链表。反转后得到的新头结点和尾结点分别存储在 reverse 数组的第 0 个和第 1 个元素中。

5. 更新原链表结构,将子链表反转后的头结点接到 pre 结点后面,尾结点接到 nex 结点前面。同时更新 pre 和 head 的值,使它们分别指向反转后的尾结点和尾结点的后继结点。

6. 当 while 循环结束后,返回 hair 结点的后继结点作为反转后的链表头结点。

**myReverse 方法**

这个方法接收两个参数,一个是 ListNode 类型的 head,代表待反转子链表的头结点;另一个是 ListNode 类型的 tail,代表待反转子链表的尾结点。该方法返回一个包含两个元素的 ListNode 数组,数组中的第 0 个元素是反转后的尾结点,第 1 个元素是反转后的头结点。

以下是 myReverse 方法的详细步骤:

1. 初始化一个 prev 结点,其值为 tail 结点的后继结点。同时定义一个指针 p,初始时指向 head 结点。

2. 使用 while 循环反转子链表,直到 prev 结点等于 tail 结点。在循环内,首先保存 p 结点的后继结点 nex,然后修改 p 结点的 next 指针使其指向 prev 结点。接着将 prev 和 p 结点向前移动一步,直至完成子链表的反转。

3. 完成反转后,返回一个包含反转后尾结点和头结点的 ListNode 数组。

通过以上两个方法的组合,我们可以实现在单向链表中反转连续 k 个节点组成的子链表的功能。

`myReverse` 方法负责反转一段连续的链表。该方法接收两个参数:`ListNode head` 和 `ListNode tail`。`head` 表示要反转的子链表的起始节点,`tail` 表示要反转的子链表的终止节点。该方法返回一个包含两个 `ListNode` 类型的数组,其中第一个元素是反转后的子链表的尾节点,第二个元素是反转后的子链表的头节点。

以下是详细的解释:

1. 首先,初始化一个 `ListNode` 类型的变量 `prev`,并将它的值设置为 `tail` 的下一个节点。这样做是因为反转链表的过程实际上是将节点原本的 `next` 指针改为指向前一个节点。因此,我们需要记录当前节点之前的节点。
   
2. 然后,定义一个 `ListNode` 类型的变量 `p`,并将它的值设置为 `head`。`p` 变量将在循环过程中逐次递增,表示当前正在处理的节点。

3. 接下来,进入一个 `while` 循环。只要 `prev` 不等于 `tail`(也就是还没到达反转子链表的末尾),就会一直执行循环内的操作。循环内的主要操作如下:
   - 先保存 `p` 节点的下一个节点到一个临时变量 `nex`。
   - 然后将 `p` 节点的 `next` 指针设置为 `prev`,这是反转链表的关键步骤,改变了链表的前后顺序。
   - 然后将 `prev` 设置为 `p`,即将 `p` 节点视为新的前驱节点。
   - 最后将 `p` 设置为 `nex`,准备处理下一个节点。

4. 当循环结束后,说明整个子链表都已经反转完毕。这时,`prev` 已经变成了反转后的子链表的尾节点,`p` 变量则指向反转后的子链表的最后一个节点(也是原子链表的首个节点)。因此,可以将 `prev` 存储到结果数组的第一个元素,将 `p` 存储到结果数组的第二个元素。

5. 最后,返回包含反转后子链表尾节点和头节点的数组。

总之,`myReverse` 方法实现了对一段连续链表的反转操作,并返回了反转后子链表的尾节点和头节点。

while (prev != tail) {
            ListNode nex = p.next;
            p.next = prev;
            prev = p;
            p = nex;
        }

反转链表,传递的tail就是新链表的起点,起点的下一个节点就是目的地(记作prev),起点记作p,while()循环上面是初始化的起点和终点的值,它是不断变化的,那么while()循环里面要更新p , prev, (nex 是下一个起点)

  • 48
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值