【反转链表系列】力扣206,92,25

一、前言

本文涉及的力扣题目,涉及简单、中等、困难三个难度

  1. 力扣206.反转链表
  2. 力扣92.反转链表 II
  3. 力扣25.K 个一组翻转链表

反转链表这类型的题目,折磨了挺久,经常弄懂了一道题,但是遇到下一道反转链表的题目还是不会。

所以我整理了三道比较经典的反转链表的题目,从浅到深一步一步领悟反转链表的处理思路。


二、反转链表

力扣206.反转链表

这是一道力扣上的简单难度的反转链表的题目,要求我们将给定的链表进行反转。

image-20241226213533846

这道题解题思路也非常简单,就是将指针反转即可,思路虽然简单,但是编写代码的时候却很容易乱。

我们思考一个问题,反转一个链表,肯定是每两个节点之间的指针先进行反转,然后遍历下来就可以了。

那么需要多少个节点指针呢?是的,需要三个!

  1. pre:表示前一个结点
  2. cur:表示当前节点
  3. next:表示下一个节点

为什么需要next指针呢?

答:是因为当precur之间的指针反转后,如果没有next指针记录cur的下一个节点,反转后就无法找到cur的下一个节点

如下图所示,第一次反转之前先记录cur的下一个节点

image-20241226214645404

那么循环中第一次反转,cur的下一个节点指向pre

image-20241226215126779

反转后,cur所指向的节点就是下一次反转的prenext指针所指向的节点,就是下一次的当前节点,next也要进行更新。

于是第一次反转后链表变成下图所示

image-20241226215724112

同理,进行第二次反转

image-20241226215806953

第三次反转

image-20241226215837196

第四次反转

image-20241226215913479

第五次反转

image-20241226215949016

curnull的时候,说明链表已经反转完成,此刻pre就是链表的头部!

要非常熟悉这个反转整个链表的流程,因为后面两道题反转链表的流程和这道题差不多,只是不是处理一整条链表而已!

记住这个结论:当链表反转完成后,pre就是链表的头部。

后面会是使用到这个结论

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode cur = head;
        ListNode pre = null;
        ListNode next = null;
        while(cur != null){
            next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }
}
  • 时间复杂度:O(n),n为链表长度
  • 空间复杂度:O(1)

相信看到这里,你已经完全掌握了链表反转的方法,后面会一直沿用这个思路去解决问题!


三、反转链表 II

力扣92.反转链表 II

反转链表 II和上一题的区别就是不是反转一整个链表,而是反转从位置 left 到位置 right 的链表节点

那么我们就必须先找到位置位于left - 1上的节点p0,然后对[left,right]位置上的链表节点进行反转即可,反转的步骤和上面的反转链表的思路一样,然后再把反转后的链表连接起来即可!

为什么要找位于left - 1上的节点?

答:因为题目要求反转[left,right]上的节点,那么原链表就被划分成了三部分,分别是原左链表、需要反转的链表、原右链表。找到位于left - 1位置上的节点是为了记录原左链表的最后一个节点的指针,方便反转后链接链表使用

反转[left,right]位置上之后,就会如下图所示,这时候需要将p0.next.next指向curp0.next指向pre,这样就完成了链表的部分反转。

image-20241228105017027

这里需要注意,假如链表的长度是1的话,那么就不会存在就不会有位于left - 1上的节点,于是我们需要定义一个哨兵节点,用作指向这个链表的头节点

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        head = new ListNode(-1, head);
        ListNode cur = head;
        ListNode pre = null;
        for(int i = 0; i < left - 1 ; i ++){
            cur = cur.next;
        }
        ListNode p0 = cur;
        cur = cur.next;
        for(int i = left; i <= right; i ++){
            ListNode next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;        
        }
        p0.next.next = cur;
        p0.next = pre;
        return head.next;
    }
}	
  • 时间复杂度:O(n),n为链表长度
  • 空间复杂度:O(1)

四、K 个一组翻转链表

力扣25.K 个一组翻转链表

这道题结合了上面两道题,需要对链表每K个为一组,进行翻转。

既然是分组,那么我们就需要先计算链表的长度,然后看看链表能分成多少组,记录一个组数。

然后根据反转链表 II的做法,进行一组一组反转即可,每次反转完一组后,需要更新p0的所在位置

image-20241228105944269

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        // 计算链表的长度
        int count = 0;
        ListNode cur = head;
        while (cur != null) {
            count++;
            cur = cur.next;
        }
        // 处理的次数
        int n = count / k;
        head = new ListNode(-1, head);
        ListNode p0 = head;
        ListNode pre = null;
        ListNode next = null;
        cur = head.next;
        while (n-- > 0) {
            for (int i = 0; i < k; i++) {
                next = cur.next;
                cur.next = pre;
                pre = cur;
                cur = next;
            }
            ListNode nxt = p0.next;
            p0.next.next = next;
            p0.next = pre;
            p0 = nxt;
        }
        return head.next;
    }
}	

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

起名方面没有灵感

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

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

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

打赏作者

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

抵扣说明:

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

余额充值