Leetcode 206 反转链表

news2025/1/17 0:59:14

反转链表

      • 准备工作
        • 1)ListNode基本结构
        • 2)初始化ListNode集合
      • 解法一:遍历创建新节点
      • 解法二:两组List,面向对象操作
      • 解法三:递归调用
      • 解法四:直接移动
      • 解法五:解法二的面向过程

Leetcode 206 反转链表

准备工作

1)ListNode基本结构
public class ListNode {
    public int val;
    public ListNode next;

    public ListNode(int val, ListNode next) {
        this.val = val;
        this.next = next;
    }

    @Override
    public String toString() {
        ListNode node = this;
        StringBuilder sb = new StringBuilder();
        while (node != null) {
            sb.append(node.val).append("->");
            node = node.next;
        }
        sb.append("NULL");
        return sb.toString();
    }
}
2)初始化ListNode集合
public class ListNodeInit {
    public static ListNode getInitList() {
        ListNode tailf = new ListNode(5, null);
        ListNode node4 = new ListNode(4, tailf);
        ListNode node3 = new ListNode(3, node4);
        ListNode node2 = new ListNode(2, node3);
        return new ListNode(1, node2);
    }
}



解法一:遍历创建新节点

新增一个ListNode newList集合,然后直接遍历目标ListNode initList集合,每遍历一个节点就创建一个新节点,并且将新节点添加到我们newList中

public class 反转链表1 {
    public static void main(String[] args) {
        ListNode initList = ListNodeInit.getInitList();
        System.out.println(initList);
        System.out.println("-----反转后-----");
        System.out.println(reverseList(initList));
    }

    private static ListNode reverseList(ListNode initList) {
        ListNode newList = null;
        ListNode p = initList;
        // 遍历到原链表的节点
        while (p != null) {
            int val = p.val;

            // 创建一个新节点,新节点的下一个节点是之前的数据(将新值添加到头部)
            newList = new ListNode(val, newList);
            p = p.next;
        }
        return newList;
    }
}



解法二:两组List,面向对象操作

构建一个包装类List集合,用于封装addFirst、removeFirst方法,思路为移除oldList头部节点,然后添加到新的newList的头部

public class 反转链表2 {

    public static void main(String[] args) {
        ListNode initList = ListNodeInit.getInitList();
        System.out.println(initList);
        System.out.println("-----反转后-----");
        System.out.println(reverseList(initList));
    }

    private static ListNode reverseList(ListNode initList) {
        List oldList = new List(initList);
        List newList = new List(null);

        while (true) {
            // 原集合不停移除头部元素
            ListNode removedNode = oldList.removeFirst();
            if (removedNode == null) {
                break;
            }
            // 新集合不停添加到头部(类比栈)
            newList.addFirst(removedNode);
        }
        return newList.head;
    }

    static class List {
        ListNode head;

        public List(ListNode head) {
            this.head = head;
        }

        /**
         * 向头部添加节点
         */
        public void addFirst(ListNode node) {
            node.next = head;
            head = node;
        }

        /**
         * 向尾部添加节点
         */
        public ListNode removeFirst() {
            ListNode removedList = head;
            if (head != null) {
                head = head.next;
            }
            return removedList;
        }
    }
}



解法三:递归调用

利用递归后续遍历的回溯,能够反向拿到每一个元素的特点,不断的向initList尾部追加我们需要的逆序链表

public class 反转链表3 {

    public static void main(String[] args) {
        ListNode initList = ListNodeInit.getInitList();
        System.out.println(initList);
        System.out.println("-----反转后-----");
        System.out.println(reverseList(initList));
    }

    private static ListNode reverseList(ListNode initList) {
        if (initList == null || initList.next == null) {
            return initList;
        }
        // initList.next.val最多为5,因为5.next.val为null。即initList.val最多为4
        ListNode node = reverseList(initList.next);

        // 第一次调用时:
        // 5 -> 4,3,2,1  &&  4 -> null
        // 第二次调用时:
        // 4 -> 3,2,1    &&  3 -> null
        // 第三次调用时:
        // 3 -> 2,1      &&  2 -> null
        // 此处递归为后续遍历,可获取5,4,3,2,1顺序的值。
        // 步骤1)拿到node节点后,将当前node和其head部分分开,将node的head部分的上一个节点赋值到node的next,
        // 步骤2)且同时切断node和其head部分之间的关联
        //
        // 补充:前面提到initList.next.val最多为5,所以initList.next.next就是5的下一个节点
        initList.next.next = initList;
        initList.next = null;
        return node;
    }
}



解法四:直接移动

有点像选择排序,对两个元素进行互换位置,只不过此处为链表,难度大于数组。通过指针的关联关系,硬操作集合本身,每拿到一个节点,都将节点移动到头部

执行流程:

指针移动效果:

public class 反转链表4 {
    public static void main(String[] args) {
        ListNode initList = ListNodeInit.getInitList();
        System.out.println(initList);
        System.out.println("-----反转后-----");
        System.out.println(reverseList(initList));
    }

    private static ListNode reverseList(ListNode o1) {
        if (o1 == null || o1.next == null) {
            return o1;
        }
        // 1、设置o1、o2、n1三者之间的关系
        ListNode o2 = o1.next;
        ListNode n1 = o1;

        while (o2 != null) {
            // 2、断开o2节点:o1的下一个节点本来是指向o2,现在直接修改为指向o2的下一个节点,所以能够断开
            o1.next = o2.next;
            // 3、o2添加到头部:o2的下一个节点是n1节点,n1表示新节点的头部
            o2.next = n1;
            // 4、修正n1的位置:在赋初值的时候,n1代表头部节点,由于上一步头部添加一个一个o2,所以n1不是头部,此处重新指向到头部
            n1 = o2;
            // 5、修正o2的位置:由于前面o2节点执行到了头部,此处将o2节点重新指向下一个需要处理的节点,即o1的下一个
            o2 = o1.next;
        }
        return n1;
    }
}



解法五:解法二的面向过程

与解法二思想相同,解法二为面向对象,此处为面向过程;
与解法四的区别为此处将原来的List集合一分为二,移动节点位置本身,没有太大的区别

public class 反转链表5 {
    public static void main(String[] args) {
        ListNode initList = ListNodeInit.getInitList();
        System.out.println(initList);
        System.out.println("-----反转后-----");
        System.out.println(reverseList(initList));
    }

    private static ListNode reverseList(ListNode initList) {
        if (initList == null || initList.next == null) {
            return initList;
        }

        // 1、初始化o1、o2、n1三者之间的关系
        ListNode n1 = null;
        ListNode o1 = initList;
        ListNode o2 = null;

        while (o1 != null) {
            // 2、标记处理节点的下一个节点:用于标记剩余待处理节点的头节点
            o2 = o1.next;
            // 3、构建新list:o1表示要处理的节点,n1为初始化节点,此处将初始化节点和在处理的o1节点进行关联
            o1.next = n1;
            // 4、修正新list的头节点:经过上面的赋值,n1位置已经向后移动一个,此处调整
            n1 = o1;
            // 5、修正待处理list的头节点:经过上面的赋值,此时o1指向新集合的头部,此时借助前面的o2,将o1的位置修正为待处理list的头部
            o1 = o2;
        }
        return n1;
    }
}

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

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

相关文章

Java异常处理集合

Java异常处理 Java语言在执行后会中断,也就是在出错位置后的代码都不会被执行,为了使非致命错误后的程序仍然能够执行,引入异常处理机制。 异常 可处理的异常用Exception表示,不可处理的异常用Error表示,通常是栈内…

ShardingSphere之ShardingJDBC客户端分库分表下

目录 ShardingJDBC实战 STANDARD标准分片策略 COMPLEX_INLINE复杂分片策略 CLASS_BASED自定义分片策略 HINT_INLINE强制分片策略 ShardingJDBC实战 上篇已经将需要用到的类、数据库表都准备好了,本篇主要介绍分片配置文件。 STANDARD标准分片策略 如果按照上篇文…

Python笔记14-实战小游戏飞机大战(上)

文章目录 功能规划安装pygame绘制游戏窗口添加玩家飞机图像屏幕上绘制飞船代码重构驾驶飞船全屏模式射击 功能规划 玩家控制一艘最初出现在屏幕底部中央的飞船。玩家可以使用箭头键左右移动飞船,还可使用空格键射击。游戏开始时,一群外星人出现在天空中…

如何从 Android SD 卡恢复已删除的照片

您是否不小心从 Android SD 卡中删除了一些照片?您是否尝试访问昨天拍摄的照片,但无论您在哪里查看都找不到它们?您的 Android 手机的外部存储是否已损坏,其内容无法访问? 在这种情况下,您应该尽快采取行动…

LV老板重夺全球首富 再次超过马斯克;新东方安徽总部大厦启用;中国与泰国签署互免签证协定

今日精选 • LV老板重夺全球首富 再次超过马斯克• 新东方安徽总部大厦启用• 中国与泰国签署互免签证协定 投融资与企业动态 • ​​传Temu将于3月在美国上线半托管业务• 国内数字支付解决方案提供商 “连连数字” 估值150亿,即将IPO• 滴滴与宁德时代宣布成立…

【Javaweb程序设计】【C00164】基于SSM的飞机订票系统(论文+PPT)

基于SSM的飞机订票系统(论文PPT) 项目简介项目获取开发环境项目技术运行截图 项目包运行、免费远程调试 项目简介 这是一个基于ssm的飞机订票系统 本系统分为前台用户模块和后台管理员模块。 前台用户模块:当游客打开系统的网址后&#xff0…

营销领域有哪些著名的模型?如销售漏斗等

一、金字塔原理 模型 适用场景:提案 沟通 思考理论 模型 来源:麦肯锡 芭芭明托 1、表达的逻辑 遵循金字塔模型的逻辑,先说结论,后说论据。所有表达的内容都可归纳出一个核心论点。这个核心论点由N个论据作为支持,而…

Qt扩展-QXlsx读写Excel配置使用

QXlsx读写Excel配置使用 一、概述1. 功能概述2. 其他维护 二、安装1. 下载源码2. 配置项目3. 测试代码4. 运行结果 一、概述 项目介绍:https://qtexcel.github.io/QXlsx/Example.html GitHub:https://github.com/QtExcel/QXlsx/tree/master QXlsx 是一个…

时序分析中的去趋势化方法

时序分析中的去趋势化方法 时序分析是研究随时间变化的数据模式的一门学科。在时序数据中,趋势是一种随着时间推移而呈现的长期变化趋势,去趋势化是为了消除或减弱这种趋势,使数据更具平稳性。本文将简单介绍时序分析中常用的去趋势化方法&a…

java自定义异常处理操作

目录 引入 介绍 一、为我们的方法创建异常类 二、使用我们定义的异常类 引入 我们在编写java代码的时候,想要在我们自己写的方法中加入我们的异常处理 介绍 一、为我们的方法创建异常类 我们先单独创建一个类,来当作我们抛出异常的类 public class AgeIllegalException ex…

JavaScript DOM属性和方法之element元素对象

在HTML DOM中,elment对象表示HTML与纳素,可以包含的节点类型有元素u节点、文本节点、注释节点。它们有响应的属性和方法,有很多都是我们之前用过的。 一、element对象属性 1、attributes 2、childNodes 3、className 4、clientWidth、of…

计算机中丢失mfc100u.dll怎么解决,详细解析mfc100u.dll丢失的解决方法

遭遇“无法找到mfc100u.dll”的错误不必过分担忧,这是一个普遍现象。许多用户在启动某些软件或游戏的时候可能会碰到这样的情况。通常,这个错误信息表明你的计算机系统中缺失了一个关键的动态链接库(DLL)文件,它可能会妨碍应用程序的顺利启动…

Centos7 升级Docker 至最新版本

卸载旧版本的Docker yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine 安装需要的软件包 yum install -y yum-utils device-mapper-persistent-data lvm2 添加Docker的yum源 #yu…

uniapp,页面当有按钮的时候,可以做一个动态的效果

效果: 这个是当点着按钮的时候没有松开按钮的效果(没有阴影) 这个是当松开按钮的效果(有阴影) 原理讲解: 这段代码实现的业务逻辑是在一个Vue组件中控制“现金”按钮的阴影效果。具体来说,它通…

Qt WebEngine模块使用(开发环境安装和程序开发)

一、Qt WebEngine Qt WebEngine_hitzsf的博客-CSDN博客 Qt WebEngine模块提供了一个Web浏览器引擎,可以轻松地将万维网上的内容嵌入到没有本机Web引擎的平台上的Qt应用程序中。Qt WebEngine提供了用于渲染HTML,XHTML和SVG文档的C 类和QML类型&#xff…

服务端开发小记02——Maven

这里写目录标题 Maven简介Maven在Linux下的安装Maven常用命令 Maven简介 Apache Maven Project是一个apache的开源项目,是用于构建和管理Java项目的工具包。 用Maven可以方便地创建项目,基于archetype可以创建多种类型的java项目;Maven仓库…

带libc源码gdb动态调试(导入glibc库使得可执行文件动态调试时可看见调用库函数源码)

文章目录 查看源码是否编译时有-g调试信息和符号表在 gdb 中加载 debug 文件/符号表将 debug 文件放入 ".debug" 文件夹通过 gdb 命令 set debug-file-directory directories GCC的gcc和g区别指定gcc/g,glibc的版本进行编译指定gcc/g的版本指定glibc的和l…

最新计算机软件毕业设计选题大全

最新计算机软件毕业设计选题大全 1、毕业设计选题 博主介绍:✌️大厂码农|毕设布道师,阿里云开发社区乘风者计划专家博主,CSDN平台Java领域优质创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。✌️ 主要项目:小…

ppt背景图片怎么设置?让你的演示更加出彩!

PowerPoint是一款广泛应用于演示文稿制作的软件,而背景图片是演示文稿中不可或缺的一部分。一个好的背景图片能够提升演示文稿的整体效果,使观众更加关注你的演示内容。可是ppt背景图片怎么设置呢?本文将介绍ppt背景图片设置的三个方法&#…

JavaScript DOM属性和方法之event事件对象

event对象代表事件的状态,比如事件在其中发生的元素,键盘按键的状态、鼠标的位置、鼠标按钮的状态,事件通常与函数结合使用,函数不会在事件发生前被执行,只有当事件被触发的时候才会执行函数。 一、句柄事件 1、oncl…