[链表]leetcode25-K 个一组反转链表

[链表]–K 个一组反转链表


题目链接

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.反转链表

  1. 定义一个 dummyHead,令 prev=dummyHead 表示已反转的最后一个节点,用于连接反转后的链表
  2. 遍历链表分组:k 个一组(不够 k 个直接返回)
  3. 为了防止走丢,还是一样的保存一下分组的尾结点 tail 的下一个节点 tailNext;
  4. 反转这一组链表:需要得到反转之后的头尾结点,可以用数组保存;
  5. 得到反转之后的头尾进行连接:
    (1)头部连接在 prev 后面,prev.next=head;
    (2)尾部连接在 tailNext 前面,tail.next=tailNext;
  6. 更新信息进行下一次的反转和连接:
    (1)prev=tail;
    (2)head=tail.next;
  7. 直到剩余个数不足 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;
    }
}

-----------------------------------------------------------------------------有始有终分割线----------------------------------------------------------------------------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值