算法通关村第二关——指定区间反转的问题解析

news2024/11/19 9:40:50

题目类型

指定区间反转

题目描述

给你单链表的头指针 head 和两个整数left 和right ,其中left <= right 。请反转从位置left到位置right的链表节点,返回反转后的链表 

 示例

输入:head = [1,2,3,4,5] , left = 2 , right = 4

输出:[1,4,3,2,5]

 图例

image.png

解题方法

1.头插法 :带头节点的反转

2. 穿针引线法:不带头节点的反转

头插法

思想

 在需要反转的区间里,每遍历到一个节点(向后遍历),让这个新节点(后面的节点)来到反转部分的起始位置(left的位置)

下图中,蓝色部分是需要进行反转的位置,即  left = 3 ,right = 6

image.png

反转流程

image.png

 代码实现
public Node reverseBetween(Node head, int left, int right){
    
    Node dummyNode = new Node(0);
    dummyNode.next = head;
    Node pre = dummyNode;
    for(int i = 0 ; i < left -1 ; i++){
        pre = pre.next;
    }
    Node cur = pre.next;
    Node next;
    for(int i = 0 ; i < right - left; i++){
        next = cur.next;
        cur.next = next.next;
        next.next = pre.next;
        pre.next = next;
    }
    return dummyNode.next;
}

理解循环代码:

整个循环的大致逻辑    是  将cur后面的节点插入到pre的后面,然后将链接补好

带图理解

 带注释版代码

    /**
     * 题目:
     * 给你单链表的头指针head和两个整数left和right,其中left <= right。请反转从位置left到位置right的链表节点,返回反转后的链表
     * 示例:
     * 输入:head = [1,2,3,4,5] ,left = 2 , right = 4
     * 输出:[1,4,3,2,5]
     *
     * 头插法(使用虚拟头节点)
     * @param head 链表头指针
     * @param left 左区间
     * @param right 右区间
     * @return 反转后的链表头节点
     */
    public Node reverseBetween(Node head , int left, int right){
        // 设置虚拟头节点
        Node dummyNode = new Node(0);
        // 将next指针指向头节点
        dummyNode.next = head;
        //  pre指针指向要操作节点的前一个位置
        Node pre = dummyNode;
        // 将pre指针走到left区间前的一个位置
        for (int i = 0; i < left - 1; i++) {
            pre = pre.next;
        }
        //  cur指针指向当前节点,要向后调整的节点(从  前---------->后)
        Node cur = pre.next;
        // next指针指向当前节点的下一个节点,即是 需要向前调整节点(从   后--->前)
        Node next;
        // 大致逻辑:将cur后面的插入到pre的后面,这样一个操作算1次
        for (int i = 0; i < right - left; i++) {
            // 将next指针指向当前节点的下一个节点
            next = cur.next;
            // 将next的下一个节点 作为 当前节点的下一个节点,即  向后移动
            cur.next = next.next;
            //  将next的下一个指针  指向  pre的后面,找到插入位置  ,即向前移动
            next.next = pre.next;
            //  将pre节点的下一个域 移动到 当前next节点上,即cur节点。表示当前一轮移动已经结束,准备下一轮的移动
            pre.next = next;
        }
        return dummyNode.next;
    }

穿针引线法

实例

如下图所示,蓝色部分是需要反转的区间,其反转前和反转后的效果如下:

image.png

 实现

         先确定好需要反转的部分,也就是下图的left和right之间,然后再将上端链表拼接起来。这种方式类似裁缝一样,找准位置,然后减下来,再缝回去。这样一来,就需要考虑如何标记下图的这四个位置了,以及如果反转left到right之间的链表。

image.png

 算法步骤

1.先将待反转的区域反转(可以使用链表反转的方法实现)

2. 把pre的next 指针指向反转以后的链表头节点,把反转以后的链表的尾节点的next指针指向succ(之前切下来剩余的后部分链表)

image.png

注意点

 链接什么时候切断,什么时候补上去;这两个先后顺序需要想清楚。

 防止链表在反转后出现环形结构,需要在切完链表形成一个子链表后,将rightNode== null

代码实现

public Node reverseBetween(Node head, int left, int right){

    Node dummyNode = new Node(0,head);
    Node pre = dummyNode;
    
    for(int i = 0 ; i < left -1; i++){
        pre = pre.next;
    }
    Node rightNode = pre.next;
    for(int i = 0; i <= right-left; i++){
        rightNode = rightNode .next;
    }
    Node leftNode = pre.next;
    Node endNode = rightNode.next;

    rightNode = null;
    
    this.reverseList(leftNode);

    pre.next = rightNode;
    leftNode.next = endNode;
    
    return dummyNode;

}
private void reverseList(Node head){
    Node pre = null;
    Node cur = head;
    while(cur != null){
      Node next = cur.next;
      cur.next = pre;
      pre = cur;
      cur = next;
    }
}

带注释代码实现

   /**
     * 穿针引线法实现链表区间反转
     *
     * @param head  链表头节点
     * @param left  左区间位置
     * @param right 右区间位置
     * @return 新的链表节点
     */
    public Node reverseBetween1(Node head , int left ,int right){
        //定义虚拟节点
        Node dummy = new Node(0,head);
        Node pre = dummy;
        // 1. 从虚拟头节点走 left-1 步 ,来到left节点的前一个节点
        for (int i = 0; i < left - 1; i++) {
            pre = pre.next;
        }
        Node rightNode = pre;
        //2.从pre 再走 right-left+1 步,来到right节点
        for (int i = 0; i < right - left + 1; i++) {
            rightNode = rightNode.next;
        }
        //3 切出一个链表
        Node leftNode = pre.next;
        Node fail = rightNode.next;
        // 这一步的意义:防止链表在反转后出现环形结构
        // 如果不将rightNode.next设置为null,则rightNode的next指针可能仍然指向以前的节点,而不是指向区间反转后的新节点
        // 断开了rightNode与fail的连接,形成了新的链表,确保了链表的完整性
        rightNode.next = null;

        // 4. 反转链表子区间
        this.reverseList(leftNode);

        // 5. 接回到原来的链表汇总
        pre.next = rightNode;
        leftNode.next = fail;

        return dummy.next;
    }

    private void reverseList(Node head){
        Node pre = null;
        Node cur = head;
        Node next;
        while (cur != null){
             next = cur.next;
             cur.next = pre;
             pre =cur;
             cur = next;
        }
    }

 

 

 

 

 

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

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

相关文章

「网络编程」传输层协议_ TCP协议学习_及原理深入理解(二 - 完结)[万字详解]

「前言」文章内容大致是传输层协议&#xff0c;TCP协议讲解的第二篇&#xff0c;续上篇TCP。 「归属专栏」网络编程 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 二、TCP协议2.9 TCP连接管理机制2.9.1 三次握手2.9.2 四次挥手2.9.3 演示查看TIME_WAIT和CLOSE_WAIT状态2.9.…

基于SpringBoot+Vue的车辆充电桩管理系统设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

MOS管的体二极管是怎么形成的

一般MOS管的源极和漏极之间会存在体二极管&#xff0c;对于N沟道的MOS管&#xff0c;体二极管由源极指向漏极。 对于PMOS管&#xff0c;体二极管由漏极指向源极&#xff0c;那么MOS管为什么会有这个体二极管呢&#xff1f; 我们看到这个N沟道MOS管的结构&#xff0c;源极和漏极…

单片机第一季:零基础12——I2C和EEPROM

目录 1&#xff0c;EEPROM 2&#xff0c;I2C 2.1&#xff0c;I2C物理层 2.2&#xff0c;I2C协议层 3&#xff0c;AT24C02介绍 4&#xff0c;代码 1&#xff0c;EEPROM 为什么需要EEPROM&#xff1f; 单片机内部的ROM只能在程序下载时进行擦除和改写&#xff0c;但是…

西安电子科技大学计算机考研分析

关注我们的微信公众号 姚哥计算机考研 更多详情欢迎咨询 西安电子科技大学&#xff08;A-&#xff09;考研难度&#xff08;☆☆☆☆&#xff09; 西安电子科技大学计算机科学与技术学院&#xff08;国家示范性软件学院&#xff09;始于1958年中央军委批复设立的导弹系统专用…

17 反显、修改、提交图书信息功能实战

前言 上节回顾 上一节&#xff0c;我们针对图书列表做了实战练习&#xff0c;主体内容包括顶部的检索区域&#xff0c;中间的el-table数据区域&#xff0c;和底部的el-pagination分页区域&#xff0c;并针对每一块做了讲解&#xff0c;还不太明白上下文的同学可以回过头去看一…

Linux标准库API

目录 1.字符串函数 2.数据转换函数 3.格式化输入输出函数 4.权限控制函数 5.IO函数 6.进程控制函数 7.文件和目录函数 1.字符串函数 2.数据转换函数 3.格式化输入输出函数 #include<stdarg.h>void test(const char * format , ...){va_list ap;va_start(ap,format…

自监督去噪:Noise2Noise原理及实现(Pytorch)

文章地址&#xff1a;https://arxiv.org/abs/1803.04189 ICML github 代码: https://github.com/NVlabs/noise2noise 本文整理和参考代码: https://github.com/shivamsaboo17/Deep-Restore-PyTorch 文章目录 1. 理论背景2. 实验结果3. 代码实现(1) 网络结构(2) 数据加载(3) 网络…

Linux--验证命令行上运行的程序的父进程是bash

1.输入以下代码&#xff1a; #include <stdio.h> #include <unistd.h> int main() {printf("hello world: pid: %d, ppid: %d\n",getpid(),getppid());return 0; }2.编译得到可执行程序​​​ 3.运行得到ppid 4.输入指令 ps axj | head -1 &&am…

Stable Diffusion ControlNet 完全指南

ControlNet 是 Stable Diffusion中的一种扩展模型&#xff0c;通过这种扩展模型&#xff0c;我们能够将参考图像的构图&#xff08;compositions &#xff09;或者人体姿势迁移到目标图像。 资深 Stable Diffusion 用户都知道&#xff0c;很难精准控制Stable Diffusion生成的图…

protobuf配置过程

一、配置过程 vs2022 第一次下载cmake 3.17 x64.msi &#xff0c; 发现没有vs2022选项。 第二次下载最新版本cmake 3.27 x64.msi &#xff0c; 发现不兼容vs2022 &#xff0c; 会闪退&#xff1b; 第三次下载了倒数第二新的版本cmake 3.26 x64.msi &#xff0c; 这次完美gen…

简单认识redis高可用实现方法

文章目录 一、redis群集三种模式二、 Redis 主从复制1、简介2、作用&#xff1a;3、流程&#xff1a;4.配置主从复制 三、Redis 哨兵模式1、简介2、原理:3、作用&#xff1a;4、哨兵结构由两部分组成&#xff0c;哨兵节点和数据节点&#xff1a;5、故障转移机制&#xff1a;6、…

C/C++ 线程池工作原理 C代码实现

1. 线程池作用 如果多次使用线程&#xff0c;那么就需要多次的创建并撤销线程。但是创建/撤销的过程会消耗资源。线程池是一种数据结构&#xff0c;其中维护着多个线程&#xff0c;这避免了在处理短时间任务时&#xff0c;创建与销毁线程的代价。即在程序开始运行前预先创建一…

day15 | 110.平衡二叉树 257.二叉树的所有路径 404.左叶子之和

文章目录 一、平衡二叉树二、[回溯小难]二叉树的所有路径三、左叶子之和 一、平衡二叉树 110.平衡二叉树 依旧是使用后序遍历来统计高度。 递归过程中&#xff0c;发现某节点的左右子树的高度差超过了1&#xff0c;我们就直接返回-1&#xff0c;不返回节点的高度了。 递归函…

C/C++开发,opencv与qt结合播放视频

目录 一、qt_ui创建 1.1 ui设置 1.2 ui及代码输出保存 二、创建工程 2.1 工程目录及编译设置 2.2 源码设计 三、编译及测试 3.1 程序编译 3.2 程序运行 首先声明&#xff0c;这是一个OpenCV 3学习文档的案例&#xff0c;但是说明有些过于省略&#xff0c;只有一些简短的代码…

ubuntu20.04终端中文显示乱码

我在配置好ubuntu20.04虚拟机以后&#xff0c;用xshell连接到终端&#xff0c;发现中文来不能显示&#xff0c;尝试过设置xshell的显示格式&#xff0c;不能解决问题。 经过研究&#xff0c;发现要修改ubuntu20.04本身的字体格式&#xff0c;解决方式如下&#xff1a; 1.修改~…

JavaBean

一、JavaBean的概念 1、JavaBean就是MVC设计模式中的model层 2、种类&#xff1a;数据bean&#xff08;pojo&#xff09;&#xff0c;逻辑bean 数据bean分为&#xff1a; 表单bean 封装表单里的参数&#xff0c;属性名字、个数和类型要和表单的参数的名字、个数和类型一致…

我对排序算法理解

排序算法一直是一个很困惑我的问题&#xff0c;早在刚开始接触 数据结构的时候&#xff0c;这个地方就很让我不解。就是那种&#xff0c;总是感觉少了些什么的感觉。一开始&#xff0c;重新来过&#xff0c;认真来学习这一部分&#xff0c;也总是学着学着就把概念记住了。过了一…

【Rust学习 | 基础系列3 | Hello, Rust】编写并运行第一个Rust程序

文章目录 前言一&#xff0c;创建项目二&#xff0c;两种编译方式1. 使用rustc编译器编译2. 使用Cargo编译 总结 前言 在开始学习任何一门新的编程语言时&#xff0c;都会从编写一个简单的 “Hello, World!” 程序开始。在这一章节中&#xff0c;将会介绍如何在Rust中编写并运…

Elasticsearch搜索引擎系统入门

目录 【认识Elasticsearch】 Elasticsearch主要应用场景 Elasticsearch的版本与升级 【Elastic Stack全家桶】 Logstash Kibana Beats Elasticsearch在日志场景的应用 Elasticsearch与数据库的集成 【安装Elasticsearch】 安装插件 安装Kibana 安装Logstash 【认…