算法通关村 | 第二关 | 黄金篇(k个一组反转)

 前言

        经过两大关的学习,hxdm一定都有所收获吧(doge),我们从什么是链表,到链表是如何构造的,再到一系列关于链表的拓展或延伸问题,最后我们来到了这里。相信大家看到之前一看就脑阔疼的链表相关问题,现在都有自己的理解了,虽然可能还是不能完整的写出结果,但大致的思路已经理清楚了,这就是进步,持续的一丢丢的进步,其效果也是显而易见的!

进入正题,我们来说说这个K个一组反转的问题! 

题目介绍

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

题目详情:

思路引导

  1. 首先,我们需要遍历整个链表来确定链表的长度。
  2. 如果链表的长度小于 k,则直接返回原链表,因为无需进行翻转。
  3. 否则,我们需要将链表分成若干组,每组包含 k 个节点。对于每一组,我们需要将其内部的节点进行翻转,然后将每组的头尾连接起来,得到翻转后的链表。
  4. 最后,将每组的头尾连接起来,并返回翻转后的链表。

         我们在之前学习两两交换链表中地结点时使用的方法有头插法,还有递归法(没有具体讲解)。对于本题具体的解法,我们可以参考两两交换的题解,即使用虚拟头结点进行头插法!

下面我们来进一步深入此场景~

解法1(迭代法)穿针引线法

         乍一看,这道题不和两两反转一样吗,只不过k=2吗,是也不是,因为k不确定,要考虑的场景较多,比如反转后首尾的连接,k的大小等条件。具体实现来说是有一定的困难的。

         还是老样子,上图(俺的图图呢?!哦,在这啊!)

 (能力有限告辞了各位!! 图只是我片面的理解,各位佬自己画一遍会更理解!)

根NB的图在这里:(教官的图)

 

代码如下:

public ListNode reverseKGroup(ListNode head, int k) {
// 创建一个虚拟头节点,方便处理边界情况
        ListNode dummy = new ListNode(0);
        dummy.next = head;

        // pre 表示当前待反转链表的前一个节点
        // end 表示当前待反转链表的尾节点
        ListNode pre = dummy;
        ListNode end = dummy;

        while (end.next != null) {
            // 让 end 走 k 步,找到待反转链表的尾节点
            for (int i = 0; i < k && end != null; i++) {
                end = end.next;
            }

            // 如果 end 为 null,说明剩余节点不足 k 个,直接结束循环
            if (end == null) {
                break;
            }

            // 记录待反转链表的头节点
            ListNode start = pre.next;
            // 记录下一组待反转链表的头节点
            ListNode next = end.next;
            // 将待反转链表与下一组链表断开
            end.next = null;

            // 反转待反转链表,并将反转后的链表与原链表连接起来
            pre.next = reverseLinkedList(start);
            start.next = next;

            // 更新 pre 和 end 的位置,准备处理下一组链表
            pre = start;
            end = pre;
        }

        return dummy.next;
    }
    // 链表反转操作
    private ListNode reverseLinkedList(ListNode head){
        ListNode pre = null;
        ListNode cur = head;
        while(cur!= null){
            ListNode temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur =temp;
        }
        return pre;
    }

解法2(头插法)

        和上面一种差不多的解法,但容易理解些 

上图

上代码

public ListNode reverseKGroup(ListNode head, int k) {
ListNode dummyNode = new ListNode(-1);
        dummyNode.next = head;
        ListNode cur = head;
        int len = 0; // 先计算出链表的长度
        while (cur != null) {
            len++;
            cur = cur.next;
        }
        int n = len / k; // 计算出有几组
        ListNode pre = dummyNode;
        cur = head;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < k - 1; j++) {
                ListNode next = cur.next;
                cur.next = cur.next.next;
                next.next = pre.next;
                pre.next = next;
            }
            pre = cur;
            cur = cur.next;
        }
        return dummyNode.next;
    }

 解法3(递归)

直接上代码了,这个递归还是比较好李姐的!

 public ListNode reverseKGroup(ListNode head, int k) {
        int count = 0;
        ListNode cur = head;
        // 计算长度
        while(cur != null){
            count++;
            cur = cur.next;
        }
        // 如果长度小于k直接返回头结点
        if(count < k){
            return head;
        }
        ListNode pre = null;
        ListNode tmp = null;
        cur = head;
        for(int i = 0;i < k;i++){
            tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }    
        head.next = reverseKGroup(tmp,k);
        return pre;
    }

        OK,链表的学习就到这里了,后续会持续更新关于一些场景题的讲解,如有遗漏和错误,还望指正。大家一起学习进步~

加油,奥利给!!!!!!!! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

計贰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值