首页 > 编程语言 >每日算法随笔:反转链表 II

每日算法随笔:反转链表 II

时间:2024-09-10 15:27:05浏览次数:1  
标签:II head 反转 next 链表 随笔 节点 left

明白了!下面我将基于你给的两种方法来详细解释题解,并展示每一步的变化过程。

题解:反转链表 II

这道题要求我们反转链表中从第 left 个节点到第 right 个节点的部分,返回反转后的链表。我们会使用两种方法:递归迭代

示例解析

  • 示例 1
    输入head = [1, 2, 3, 4, 5], left = 2, right = 4
    输出[1, 4, 3, 2, 5]

    在这个例子中,链表 [1, 2, 3, 4, 5] 中,需要反转位置 24 的节点,最终得到 [1, 4, 3, 2, 5]

  • 示例 2
    输入head = [5], left = 1, right = 1
    输出[5]

    单个节点的链表,不需要反转,直接返回原链表。


解法 1:迭代法

迭代法通过调整链表中的指针,逐步实现反转目标区间的节点。

步骤

  1. 初始化虚拟节点:创建一个 dummy 节点指向链表头部,方便处理 left 在第一个节点的情况。
  2. 找到 left 前的节点:通过遍历找到第 left 个节点之前的节点 pre
  3. 反转链表区间:通过调整节点的 next 指针,依次反转区间内的节点。
  4. 返回结果:最后返回 dummy.next,即反转后的链表。

代码

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        // 创建虚拟节点
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        
        // 找到 left 前面的节点
        ListNode pre = dummy;
        for (int i = 0; i < left - 1; i++) {
            pre = pre.next;
        }
        
        // 开始反转区间
        ListNode curr = pre.next;
        ListNode next = null;
        for (int i = 0; i < right - left; i++) {
            next = curr.next;
            curr.next = next.next;
            next.next = pre.next;
            pre.next = next;
        }
        
        return dummy.next;
    }
}

示例变化过程

  1. 初始化:创建虚拟节点 dummy,并找到 left 之前的节点 pre,即 pre = 1

    初始链表: [1 -> 2 -> 3 -> 4 -> 5]
    
  2. 第一次反转

    • 当前 curr = 2next = 3
    • next 节点插入到 pre 后面。
    反转后: [1 -> 3 -> 2 -> 4 -> 5]
    
  3. 第二次反转

    • 当前 curr = 2next = 4
    • next 节点插入到 pre 后面。
    最终结果: [1 -> 4 -> 3 -> 2 -> 5]
    

解法 2:递归法

递归法的核心思想是逐步缩小反转范围,最终通过递归栈返回反转后的子链表。

步骤

  1. 递归终止条件:当 left == 1 时,调用反转前 right 个节点的函数。
  2. 递归:每次向下递归,直到找到第 left 个节点,然后开始反转前 right-left+1 个节点。
  3. 返回结果:通过递归调用栈反转链表,并将各部分重新连接。

代码

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        // 当left == 1时,调用反转前right个节点的函数
        if (left == 1) {
            return reverseN(head, right);
        }
        // 递归前进到left - 1的位置
        head.next = reverseBetween(head.next, left - 1, right - 1);
        return head;
    }
    
    // 反转前n个节点的子函数
    private ListNode reverseN(ListNode head, int n) {
        if (n == 1) {
            return head;
        }
        ListNode newHead = reverseN(head.next, n - 1);
        head.next.next = head;
        head.next = null;
        return newHead;
    }
}

示例变化过程

  1. 递归调用

    • 第一次递归:left = 2, right = 4,递归调用 head = 2
    • 第二次递归:left = 1, right = 3,开始反转前 3 个节点。
  2. 第一次反转

    • 反转 [2 -> 3 -> 4] 中前 3 个节点,得到 [4 -> 3 -> 2]
    反转后: [1 -> 4 -> 3 -> 2 -> 5]
    
  3. 返回结果:递归结束后,返回完整的反转链表 [1 -> 4 -> 3 -> 2 -> 5]


总结

  • 迭代法:通过调整指针逐步反转目标区间,时间复杂度为 O(n),只需一趟扫描链表。
  • 递归法:利用递归栈反转链表,代码简洁,但可能会带来栈空间的额外开销。

两种方法在解决这类链表局部反转的问题时都很高效,选择使用哪种方法可以根据实际需求和个人习惯。

标签:II,head,反转,next,链表,随笔,节点,left
From: https://www.cnblogs.com/yubaibaibubai/p/18406456

相关文章

  • 每日算法随笔:反转链表
    题解:反转链表这道题目要求我们将一个单链表进行反转,返回反转后的链表。链表的反转可以通过迭代和递归两种方法来实现。下面我们将详细解释这两种方法,并通过例子演示每一步的变化过程。方法一:迭代法思路:我们用三个指针来完成链表的反转:prev表示前一个节点,curr表示当前节......
  • Java-实现双向环形链表
            双向链表是一种常用的数据结构,其特点是每个节点不仅包含数据,还持有指向前一个节点和后一个节点的指针。与普通双向链表不同的是,它的哨兵节点的prev指向最后一个元素,而最后一个元素的next指向哨兵。        具体双向普通链表可以参考我的上篇文章,这里......
  • [Python手撕]排序链表
    #Definitionforsingly-linkedlist.#classListNode:#def__init__(self,val=0,next=None):#self.val=val#self.next=nextclassSolution:defsortList(self,head:Optional[ListNode])->Optional[ListNode]:def......
  • PARTIII-Oracle事物管理-数据并发性和一致性
    9.数据并发性和一致性本章解释了Oracle数据库如何在多用户数据库环境中维护一致性的数据。本章包含以下部分:数据并发性和一致性的介绍Oracle数据库事务隔离级别的概述Oracle数据库锁定机制的概述自动锁定的概述手动数据锁定的概述用户定义锁的概述9.1.数据并发性和一......
  • IIS:部署VUE前后端分离,重写URL
    启用IIS路由和ULR重写功能  详细过程:“IIS:URLrewrite转发请求-le.li-博客园(cnblogs.com)”配置URL重写后,与网站同级别路径有个web.config <?xmlversion="1.0"encoding="UTF-8"?><configuration><system.webServer><rewrite>......
  • 数据结构—单链表的基本操作
    目录1.单链表的初始化2.求表长操作3.按序号查找结点4.按值查找表结点5.插入结点操作6.删除结点操作7.头插法建立单链表8.尾插法建立单链表1.单链表的初始化 带头结点: boolInitList(LinkList&L){       //带头结点的单链表的初始化  L=(......
  • C ++ 从单链表到创建二叉树到二叉树的遍历(结构体)
    首先我们要了解二叉树的数据结构是什么,本质上二叉树是一个有两个节点的链表,我们先了解的单链表的相关定义单链表创建一个朴素的单链表#include<iostream>usingnamespacestd;structNode{intval;Node*next;Node(intx):val(x),next(nullptr){}......
  • IIS标识介绍
    原文链接:https://blog.csdn.net/weixin_30607659/article/details/95294969应用程序池的标识是运行应用程序池的工作进程所使用的服务帐户名称。默认情况下,应用程序池以NetworkService 用户帐户运行,该帐户拥有低级别的用户权限。您可以将应用程序池配置为以 Windows Server......
  • 力扣刷题——3177. 求出最长好子序列 II
    根据题意,暴力做法不可取,因为至少要对遍历位置之前的位置,以及不同的子序列阈值(跟k对应的那个)做循环。于是就能够想到使用动态规划的手段去解决问题,考虑需要保存的两个状态,当前序列末尾的数字、子序列阈值,设计一个二维的dp数组dp[i][j],其中i为位置索引,指代当前在nums数组中遍历的位......
  • IIS 屏蔽Help页面和Swagger
    1、MVC屏蔽HelP页面暴露API接口方法:找到目录下的 Areas\HelpPage\Views\Help的Index.cshtml注释如代码中@[email protected]@usingSystem.Web.Http.Description@[email protected]......