【刷题之路Ⅱ】LeetCode 92. 反转链表 II

news2024/11/25 14:27:01

【刷题之路Ⅱ】LeetCode 92. 反转链表 II

  • 一、题目描述
  • 二、解题
    • 1、方法1——穿针引线法
      • 1.1、思路分析
      • 1.2、代码实现
    • 2、方法2——针对进阶的头插法
      • 2.1、思路分析
      • 2.2、代码实现

一、题目描述

原题连接: 92. 反转链表 II
题目描述:
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

示例 1:

在这里插入图片描述
输入: head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]

示例 2:

**输入:**head = [5], left = 1, right = 1
输出:[5]

提示:
链表中节点数目为 n
1 <= n <= 500
-500 <= Node.val <= 500
1 <= left <= right <= n

进阶: 你可以使用一趟扫描完成反转吗?

二、解题

1、方法1——穿针引线法

1.1、思路分析

其实这一题与"206. 反转链表"的区别就在于,206题是要求我们把整个链表都反转,而这一题只要求我们把链表的一部分反转。所以反转部分我们就沿用206题的方法即可,还不知道思路的可以转到【刷题之路】LeetCode 206. 反转链表。
而为了反转之后还能连接回原链表,我们分别记录反转部分的链表的表头的前一个节点和表尾的后一个节点,如下图中绿色节点标注:
在这里插入图片描述
而又因为反转部分可能还包含了头节点,所以为了方便操作我们需要额外的创建一个辅助的哑结点,指向我们链表的头节点:
在这里插入图片描述
然后我们一共需要四个指针:pre、leftNode、rightNode,next,分别记录反转部分的前一个节点、反转部分的头节点、分转部分的尾节点和反转部分的后一个节点:
在这里插入图片描述
而当我们把反转部分的链表反转完毕之后,只需要更改相应的指针的指向即可:
在这里插入图片描述
即pre->next = rightNode,leftNode->next = next。
(这里反转部分的头节点和尾节点的位置虽然发生了变化,但rightNode和leftNode的指向并没有变化)。

1.2、代码实现

有了以上思路,那我们写起代码来也就水到渠成了:

// 沿用206题的迭代版的链表反转方法
void reverseList(struct ListNode* head){
    if (NULL == head) {
        return NULL;
    }    
    struct ListNode *Pre = NULL;
    struct ListNode *Cur = head;
    struct ListNode *Next = head->next;
    
    while (Cur) {
        // 翻转
        Cur->next = Pre;

        // 迭代
        Pre = Cur;
        Cur = Next;
        if (Next) {
            Next = Next->next;
        }
    }
}

struct ListNode* reverseBetween(struct ListNode* head, int left, int right) {
    if (NULL == head || NULL == head->next) {
        return head;
    }
    // 先创建一个辅助的哑结点
    struct ListNode *dumbNode = (struct ListNode*)malloc(sizeof(struct ListNode));
    dumbNode->val = -1;
    dumbNode->next = head;
    struct ListNode *cur = dumbNode;
    struct ListNode *leftNode = head;
    struct ListNode *rightNode = NULL;
    struct ListNode *pre = dumbNode; // 记录leftNode的前一个节点
    // 因为头节点也可能包含在反转部分,所以pre初始化时应该指向dumbNode
    struct ListNode *next = NULL; // 记录rightNode的下一个节点
    int len = 0; // 记录链表的长度
    
    // 先找到各个节点
    while (cur) {
        len++;
        if (len == left) {
            pre = cur;
            leftNode = pre->next;
        }
        if (len == right + 1) {
            rightNode = cur;
            next = rightNode->next;
        }
        cur = cur->next;
    }

    // 断开链表
    pre->next = NULL;
    rightNode->next = NULL;

    // 反转链表
    reverseList(leftNode);

    // 接回原来的链表
    pre->next = rightNode;
    leftNode->next = next;
    return dumbNode->next;
}

2、方法2——针对进阶的头插法

方法1的效率其实并不是很高,因为如果left和right刚好是原链表的头和尾时,我们前后一共需要遍历两次链表,分别是找各个节点一次和反转链表一次。
那有没有一种方法能一次遍历解决问题呢?

2.1、思路分析

针对进阶提出的:你可以使用一趟扫描完成反转吗?,其实有一种解决方案就是“头插”。
我们可以将反转部分的各个节点头插到反转部分的前一个节点,具体做法如下:
我们需要三个指针pre、cur和next,pre指针永远指向反转部分的前一个节点,cur则用来遍历反转部分,next永远指向cur的下一个节点:
在这里插入图片描述
而接下来的反转操作就要有些讲究了:
第一步,先将cur的next指向next的next:
在这里插入图片描述
第二步,将next的next指向pre->next:
在这里插入图片描述
注意这里的next的next指向的一定是pre的next,而不是cur,因为cur的位置是一直往后走的,只有指向pre的next才是头插。
第三步,将pre的next指向next
在这里插入图片描述
最后我们的cur其实并不用再往后走了。
以上操作总共需要执行right - left次,因为一共有right - left个节点需要反转。
最后返回dumbNode的next即可。

2.2、代码实现

有了以上思路,那我们写起代码来也就水到渠成了:

struct ListNode* reverseBetween(struct ListNode* head, int left, int right) {
    if (NULL == head || NULL == head->next) {
        return head;
    }
    // 先创建一个辅助的哑结点
    struct ListNode *dumbNode = (struct ListNode*)malloc(sizeof(struct ListNode));
    dumbNode->val = -1;
    dumbNode->next = head;
    struct ListNode *cur = dumbNode;
    struct ListNode *pre = dumbNode; // 记录反转部分的前一个节点
    struct ListNode *next = NULL; // cur的下一个节点

    // 先定位pre,只需让pre往后走left - 1次即可
    int i = 0;
    for (i = 0; i < left - 1; i++) {
        pre = pre->next;
    }
    cur = pre->next;
    next = cur->next;

    // 再进行反转,总共需要反转right - left次
    for (i = 0; i < right - left; i++) {
        next = cur->next;
        cur->next = next->next;
        next->next = pre->next;
        pre->next = next;
    }
    return dumbNode->next;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/478237.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于全过程通道相关像素值顺序的彩色图像可逆数据隐藏

文献学习&#xff1a; 基于全过程通道相关像素值顺序的彩色图像可逆数据隐藏 原文题目&#xff1a; Reversible data hiding for color images based on pixel value order of overall process channel. 发表期刊&#xff1a; Signal Processing&#xff08;中科院二区&#xf…

AOP(面向切面编程)

3、AOP 3.1、场景模拟 3.1.1、声明接口 声明计算器接口Calculator&#xff0c;包含加减乘除的抽象方法 public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j); }3.1.2、创建实现类 public class Calcul…

osgGA::CameraManipulator类computeHomePosition函数分析

osgGA::CameraManipulator类computeHomePosition函数代码如下&#xff1a; void CameraManipulator::computeHomePosition(const osg::Camera *camera, bool useBoundingBox) {if (getNode()){osg::BoundingSphere boundingSphere;OSG_INFO<<" CameraManipulator::…

继续细说文件

先来了解几个函数&#xff1a; fopen&#xff0c;这个函数有2个参数分别为&#xff08;字符串也就是要记得打引号&#xff09;路径&#xff0c;和&#xff08;字符串&#xff09;操作模式&#xff0c;返回值为FILE类型的指针&#xff0c;也就是一个指向文件信息的结构的指针&a…

Java 基础入门篇(五)——— 面向对象编程

文章目录 一、面向对象的思想二、类的定义与对象的创建三、对象内存分配情况 ★ 3.1 两个对象的内存图3.2 两个变量指向同一个对象内存图 四、构造器4.1 构造器的格式与分类4.2 构造器的调用 五、 this 关键字六、封装七、标准JavaBean补充&#xff1a;局部变量和成员变量的区别…

【计算机网络详解】——物理层(学习笔记)

&#x1f4d6; 前言&#xff1a;今天我们将一起探索电脑网络中最基础的一层&#xff0c;物理层。从摩斯电码到光纤传输的高速互联网时代&#xff0c;物理层在不断发展和创新。让我们一起深入到网络通讯的本质&#xff0c;探究物理层与我们的日常联系密不可分的原因。 目录 &…

面试篇:Spring

一、Spring框架的单例bean是线程安全的吗&#xff1f; 1、Spring框架中的bean是单例的吗&#xff1f; spring框架中的bean是单例的&#xff0c;在默认情况下是singleton模式&#xff0c;即单例模式。如果需要更改则可以在Scope注解设置为prototype为多例模式。 singleton:bea…

ECharts---X轴文字显示不全

原因&#xff1a; X轴标签文字过多导致显示不全解决方法&#xff1a;(一)xAxis 中添加 xAxis.axisLabel 属性 axisLabel是用来设置x轴的刻度以及一些参数的设置&#xff1a; (1)interval设置的是间隔数&#xff0c;把x轴分成10个间隔&#xff0c;根据x轴的数据自动划分份数值…

【计算机专业漫谈】【计算机系统基础学习笔记】W1-计算机系统概述

利用空档期时间学习一下计算机系统基础&#xff0c;以前对这些知识只停留在应试层面&#xff0c;今天终于能详细理解一下了。参考课程为南京大学袁春风老师的计算机系统基础MOOC&#xff0c;参考书籍也是袁老师的教材&#xff0c;这是我的听课自查资料整理后的笔记&#xff0c;…

【Java笔试强训 14】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;计算日期…

web小游戏开发:华容道(一)

web小游戏开发:华容道(一) 华容道htmlcss素材原图素材验证游戏关卡华容道 老顾儿时的记忆啊,也是一个经典的益智游戏。 游戏规则就不用再介绍了吧,就是让曹操移动到曹营就算胜利。 CSDN 文盲老顾的博客,https://blog.csdn.net/superrwfei html 经过上次的扫雷,大家应…

Prometheus 监控初体验

最近由于要对Splunk 实现Prometheus 监控,下面先实践一下: 0: 先看架构图: 1: 安装: docker run -d -p 9090:9090 -v ~/docker/prometheus/:/etc/prometheus/ prom/prometheus 执行上面的 命令,发现prometheus docker 启动不起来,(原因是Mac 里的文件权限,或者是path

《嵌入式系统》知识总结4:STM32时钟源

此图说明了STM32的时钟走向&#xff0c;从图的左边开始&#xff0c;从时钟源一步步分配到外设时钟。 时钟源分类 从时钟频率来说&#xff0c;分为高速时钟和低速时钟&#xff0c;高速时钟是供给芯片主体的主时钟&#xff0c;而低速时钟只是供 给芯片中的RTC&#xff08;实时时…

Django请求生命周期

前言 django是一个web框架&#xff0c;在这之前的文章中&#xff0c;我们推导了python web框架的实现过程&#xff0c;也了解了客户端浏览器输入网址回车后发生了啥事&#xff0c;为了更加理解django的工作流程&#xff0c;本文将介绍客户端浏览器访问django后端在django框架中…

R语言多元数据统计分析在生态环境中的实践

生态环境领域研究中常常面对众多的不同类型的数据或变量&#xff0c;当要同时分析多个因变量&#xff08;y&#xff09;时需要用到多元统计分析&#xff08;multivariate statistical analysis&#xff09;。多元统计分析内容丰富&#xff0c;应用广泛&#xff0c;是非常重要和…

如何使用OpenVPN搭建局域安全网

前言: 由于在使用SpringCloud的时候把注册中心部署到内网中的一个服务器器上,由于这个服务器和我当前使用的网络的网关在同一个局域网内内,但是我电脑不在.主要现象就是我的电脑能ping通服务器,但是服务器不能ping通我的电脑 正文: 服务器端安装方式一: 去这个仓库下载一个open…

【人脸检测】——YOLO5Face: Why Reinventing a Face Detector论文浅读

人脸检测&#xff0c; yolov5 主要讨论的问题&#xff1a; 用通用的目标检测模型做人脸检测&#xff0c;而不一定需要一些专业设计的结构 摘要 最近几年在使用卷积神经网络进行人脸检测方面取得了巨大的进展。尽管许多人脸检测器使用专门用于检测人脸的设计&#xff0c;但我们…

【CTF WriteUp】2023数字中国创新大赛网络数据安全赛道决赛WP(2)

2023数字中国创新大赛网络数据安全赛道决赛WP(2) 数据分析题目 菜的要死&#xff0c;各种不会&#xff0c;答案也不全&#xff0c;凑合吧 数据分析-bankmail 流量为邮件通信流量 将其中邮件部分导出&#xff0c;保存为eml文件并打开&#xff0c;看到Alice给Bob的第一封邮件…

收藏的一些好用的网站

一、PPT模板 网址&#xff1a;https://pptmon.com/ PPTMON - Free PowerPoint Templates and Google Slides Themes 是一个提供 PowerPoint 模板和图标素材下载的网站。该网站上有大量的 PowerPoint 模板&#xff0c;可供用户根据自己的需要进行选择和下载。此外&#xff0c;该…

二叉树OJ题目合集(单值、对称、平衡、构建加遍历)

目录 前言&#xff1a; 一&#xff1a;单值二叉树 二&#xff1a;二叉树遍历 核心点 (1)前序 (2)中序 (3)后序 三&#xff1a;判断两颗树是否相同 四&#xff1a;判断二叉树是否对称 五&#xff1a;判断一颗树是否为另一颗树的子树 六&#xff1a;平衡二叉树 七&…