【链表】Leetcode 92. 反转链表 II【中等】

反转链表 II

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

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

解题思路1

1、遍历链表:

  • 找到 left 前面的节点(preLeft),以及 left 节点本身(leftNode)。
  • 找到 right 节点(rightNode),以及 right 后面的节点(postRight)。
    2、反转部分链表:
  • 将 leftNode 到 rightNode 之间的节点进行反转。
    3、重新连接:
  • 将 preLeft 的 next 指向 rightNode。
  • 将 leftNode 的 next 指向 postRight。

java实现1

public class ReverseBetween {

    public static class ListNode {
        int val;
        ListNode next;

        ListNode(int x) {
            val = x;
        }
    }

    public ListNode reverseBetween(ListNode head, int left, int right) {
        // 创建虚拟头节点,简化边界处理
        ListNode dummyNode = new ListNode(-1);
        dummyNode.next = head;

        ListNode preLeft = dummyNode;
        // 第 1 步:找到 left 节点的前一个节点 pre
        for (int i = 0; i < left - 1; i++) {
            preLeft = preLeft.next;
        }

        // 第 2 步:找到 right 节点
        ListNode rightNode = preLeft;
        for (int i = 0; i < right - left + 1; i++) {
            rightNode = rightNode.next;
        }

        // 第 3 步:切断出一个子链表(截取链表)
        ListNode leftNode = preLeft.next;
        ListNode postRight = rightNode.next;

        // 切断链接
        preLeft.next = null;
        rightNode.next = null;

        // 第 4 步:反转链表的子区间
        reverseLinkedList(leftNode);

        // 第 5 步:接回到原来的链表中
        preLeft.next = rightNode;
        leftNode.next = postRight;

        return dummyNode.next;
    }

    private void reverseLinkedList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;

        while (cur != null) {
            ListNode next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
    }


    public static void main(String[] args) {
        ReverseBetween reverseBetween = new ReverseBetween();

        // 创建示例链表 1->2->3->4->5
        ListNode head = new ListNode(1);
        head.next = new ListNode(2);
        head.next.next = new ListNode(3);
        head.next.next.next = new ListNode(4);
        head.next.next.next.next = new ListNode(5);

        // 测试反转第2到第4个节点
        ListNode newHead = reverseBetween.reverseBetween(head, 2, 4);
        printList(newHead); // 输出: 1->4->3->2->5
    }

    // 辅助方法:打印链表
    public static void printList(ListNode head) {
        ListNode current = head;
        while (current != null) {
            System.out.print(current.val);
            if (current.next != null) {
                System.out.print("->");
            }
            current = current.next;
        }
        System.out.println();
    }
}

时间空间复杂度1

  • 时间复杂度:O(N),其中 N是链表总节点数。最坏情况下,需要遍历整个链表。

  • 空间复杂度:O(1)。只使用到常数个变量。

解题思路2

解题思路1缺点是:如果 left 和 right 的区域很大,恰好是链表的头节点和尾节点时,找到 left 和 right 需要遍历一次,反转它们之间的链表还需要遍历一次,虽然总的时间复杂度为 O(N),但遍历了链表 2 次。

1、初始化和定位:

  • 使用指针 pre 遍历到 left 前一个节点,定位到反转区间的前一个节点。
    局部反转:

2、使用三个指针 pre、cur 和 next 进行反转操作:

  • pre 指向反转区间的前一个节点。

  • cur 指向当前需要反转的节点。

  • next 指向当前节点的下一个节点,用于在反转过程中进行位置交换。
    3、反转区间:

  • 通过逐个移动 cur 和 next 节点的位置,在反转区间内执行交换操作,完成局部反转。

图解:
在这里插入图片描述

在这里插入图片描述
核心代码分析:

  • curr:指向待反转区域的第一个节点 left;
  • next:永远指向 curr 的下一个节点,循环过程中,curr 变化以后 next 会变化;
  • pre:永远指向待反转区域的第一个节点 left 的前一个节点,在循环过程中不变。
   			// 先将 curr 的下一个节点记录为 next;
            next = cur.next;
            //执行操作1:把 curr 的下一个节点指向 next 的下一个节点
            cur.next = next.next;
            //执行操作2:把 next 的下一个节点指向 pre 的下一个节点
            next.next = pre.next;
            //执行操作3:把 pre 的下一个节点指向 next
            pre.next = next;

在这里插入图片描述
在这里插入图片描述
后续同理
在这里插入图片描述
在这里插入图片描述

java实现2

public class ReverseBetween {

    public static class ListNode {
        int val;
        ListNode next;

        ListNode(int x) {
            val = x;
        }
    }

    public ListNode reverseBetween(ListNode head, int left, int right) {
        // 设置 dummyNode 是这一类问题的一般做法
        ListNode dummyNode = new ListNode(-1);
        dummyNode.next = head;
        ListNode pre = dummyNode;
        //找到pre结点
        for (int i = 0; i < left - 1; i++) {
            pre = pre.next;
        }
        //当前current节点
        ListNode cur = pre.next;
        ListNode next;
        
        for (int i = 0; i < right - left; i++) {
            // cur的下一个节点赋值给next
            next = cur.next;
            //cur指向next指向的节点
            cur.next = next.next;
            //next指向pre指向的节点
            next.next = pre.next;
            //pre指向next
            pre.next = next;
        }
        return dummyNode.next;
    }


    public static void main(String[] args) {
        ReverseBetween reverseBetween = new ReverseBetween();

        // 创建示例链表 1->2->3->4->5
        ListNode head = new ListNode(1);
        head.next = new ListNode(2);
        head.next.next = new ListNode(3);
        head.next.next.next = new ListNode(4);
        head.next.next.next.next = new ListNode(5);

        // 测试反转第2到第4个节点
        ListNode newHead = reverseBetween.reverseBetween(head, 2, 4);
        printList(newHead); // 输出: 1->4->3->2->5
    }

    // 辅助方法:打印链表
    public static void printList(ListNode head) {
        ListNode current = head;
        while (current != null) {
            System.out.print(current.val);
            if (current.next != null) {
                System.out.print("->");
            }
            current = current.next;
        }
        System.out.println();
    }
}

时间空间复杂度2

  • 时间复杂度:O(N),其中 N 是链表总节点数。最多只遍历了链表一次,就完成了反转。

  • 空间复杂度:O(1)。只使用到常数个变量。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

将 KNX 接入 Home Assistant 之一 准备硬件

不久前有人小伙伴买了usb转knx ,详情请看 一个 usb 转 knx 的模块 然后想通过这个设备接入 Home Assistant。 后来了解了一下 Home Assistant 并不直接支持 usb转KNX的接入&#xff0c;需要通过KNXD插件转接才行。 然而尝试了很多次叶没有成功&#xff0c;使用西门子的usb接口以…

【香橙派AIpro】开箱测评

1.板子开箱 哟&#xff0c;看起来还不错哦&#xff01;&#xff01;&#xff01; 收货清单&#xff1a; 主板*1 1.5m数据线*1 充电头*1 1.1.充电头 近65W的充电头&#xff0c;不错不错。 1.2.主板 1.2.1.上面 哇噢&#xff0c;还送了2.4/5G的WiFi和蓝牙天线。 emm&#xf…

React-入门

React由Meta公司研发&#xff0c;是一个用于构建Web和原生交互界面的库 既可以写基于浏览器的应用&#xff0c;还可以写苹果和安卓的原生应用 优势 开发环境搭建 create-react-app是一个快速创建React开发环境的工具&#xff0c;底层是由Webpack构建&#xff0c;封装了配置细…

redis数据类型之string,list

华子目录 key操作说明SCAN cursor [MATCH pattern] [COUNT count]dump与restorekeys 通配符 示例演示 string说明setbit key offset valuegetbit key offsetsetrange key offset value List结构图相关命令lrem key count valueltrim key count value示例&#xff1a;使用 LTRIM…

图形学概述

图形学应用 游戏 游戏的画面好坏如何鉴定呢&#xff1f; 看游戏画面是否够亮&#xff1a;渲染中全局光照的好坏 《只狼》 为什么卡通游戏画面看起来是卡通的呢&#xff1f; 《无主之地3》 这些都是图形学需要着手解决的问题 电影 电影《黑客帝国》的特效也是通过计算机…

Python 全栈体系【四阶】(五十四)

第五章 深度学习 十二、光学字符识别&#xff08;OCR&#xff09; 3. 文字识别技术 3.1 CRNNCTC(2015) CRNN&#xff08;Convolutional Recurrent Neural Network&#xff09;即卷积递归神经网络&#xff0c;是DCNN和RNN的组合&#xff0c;专门用于识别图像中的序列式对象。…

《python编程从入门到实践》day40

# 昨日知识点回顾 编辑条目及创建用户账户 暂没能解决bug&#xff1a; The view learning_logs.views.edit_entry didnt return an HttpResponse object. It returned None instead.# 今日知识点学习 19.2.5 注销 提供让用户注销的途径 1.在base.html中添加注销链接 …

[笔试强训day09]

文章目录 BC146 添加逗号DP2 跳台阶JZ61 扑克牌顺子解法一&#xff1a;排序模拟解法二&#xff1a;规律哈希 BC146 添加逗号 BC146 添加逗号 #include<iostream> #include<string>using namespace std;int main() {string s;cin>>s;string ans;for(int i0;i…

2024年上半年系统架构设计师——案例第二题——UML相关

这个只记到一个大概了 主题干&#xff0c;说明人员访客系统 题目1 9分 问序列图信息类型和特点 题目2 序列图填空 好像是10分吧 访客系统的序列图 题目3 6分 说明软件分析和设计时的和UML图有关原则&#xff1f;

揭秘爬虫技术:从请求到存储的全方位解析

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、爬虫初探&#xff1a;请求与响应 二、数据解析&#xff1a;从混乱中提炼价值 三、数据…

微软发布多模态模型Phi-3-vision,仅4.2B,小模型大潜力

前言 在大型语言模型&#xff08;LLM&#xff09;领域&#xff0c;模型参数规模与性能之间一直存在着密切的联系。近年来&#xff0c;虽然参数规模不断攀升&#xff0c;但随之而来的训练成本和推理成本也成为了制约模型发展的瓶颈。为了打破这一困境&#xff0c;微软推出了 Ph…

Livox-SDK2 用vs2017编译

Livox-SDK2 Livox-SDK2代码去上面下载&#xff0c;文章中给出的是用vs2019进行编译的&#xff0c;生成项目时用的 > cmake .. -G "Visual Studio 16 2019" -A x64 但如果我想用vs2017进行编译&#xff0c;那么只需要将上面语句改为如下&#xff1a; cmake .. -…

【数据结构】快速排序C语言

目录 前言 一、快排思想过程 二、算法思路 三、代码实现 C语言实现&#xff1a; C实现: 总结 前言 排序是一个相对复杂的过程,进一步思考排序这个问题,我们可以借助分治的思想来解决这个问题, 什么叫分治呢?就是把大问题化成小问题,进而缩小问题的规模,并且大问题和小问…

牛客NC166 连续子数组的最大和(二)【中等 前缀和数组+动态规划 Java/Go/PHP/C++】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/11662ff51a714bbd8de809a89c481e21 思路 前缀和数组动态规划Java代码 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规…

课时138:变量进阶_变量实践_综合案例

2.1.3 综合案例 学习目标 这一节&#xff0c;我们从 免密认证、脚本实践、小结 三个方面来学习 免密认证 案例需求 A 以主机免密码认证 连接到 远程主机B我们要做主机间免密码认证需要做三个动作1、本机生成密钥对2、对端机器使用公钥文件认证3、验证手工演示 本地主机生成…

MyBatis报错:TypeException Could not set parameters for mapping问题解决

MyBatis报错&#xff1a;TypeException: Could not set parameters for mapping问题解决 问题收录 org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{proper…

【详细介绍下PostgreSQL】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

考研数学|强化跟「张宇」还是「武忠祥」?看这一篇!

考研数学强化阶段是备考过程中非常关键的一环&#xff0c;它不仅要求学生巩固和深化基础知识&#xff0c;还要求学生能够灵活运用所学知识解决复杂问题。 在选择张宇老师或武忠祥老师的高数强化课时&#xff0c;你可以考虑以下几个方面。 首先每位学生都有自己独特的学习风格…

图片数据增强-resize(不同插值)、各种模糊

各种不同的模糊处理 import os import cv2def apply_blur_to_images(input_folder_path, output_folder_path):# 遍历文件夹下的所有文件for filename in os.listdir(input_folder_path):# 检查文件类型是否为图片if filename.endswith(.jpg) or filename.endswith(.jpeg) or …

探索演进:了解IPv4和IPv6之间的区别

探索演进&#xff1a;了解IPv4和IPv6之间的区别 在广阔的互联网领域中&#xff0c;设备之间的通信依赖于一组独特的协议来促进连接。前景协议中&#xff0c;IPv4&#xff08;Internet 协议版本 4&#xff09;和 IPv6&#xff08;Internet 协议版本 6&#xff09;是数字基础设施…