024.两两交换链表中的节点,用递归和 while 循环

news2024/11/13 12:54:22

题意

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

难度

中等

示例

输入:head = [1,2,3,4]
输出:[2,1,4,3]

分析 1

看到这道题,我们要先搞清楚什么是两两交换,比如 1->2->3->4,交换后就是 2->1->4->3。

第一个和第二个交换,第三个和第四个交换,以此类推。

我们可以用递归来解决这个问题,递归的终止条件是当前节点或者下一个节点为空,那么递归的返回值就是当前节点。

比如说 1 和 2 交换后, 2 的 next 指向 1,1 的 next 指向下一次交换后的结果。

我们来看题解的代码:

class Solution {
    public ListNode swapPairs(ListNode head) {
        // 递归终止条件:链表没有节点或只有一个节点
        if (head == null || head.next == null) {
            return head;
        }
        
        // 准备交换
        ListNode firstNode = head;
        ListNode secondNode = head.next;

        // 递归处理剩下的节点
        firstNode.next = swapPairs(secondNode.next);

        // 交换
        secondNode.next = firstNode;

        // 返回交换后新的头节点
        return secondNode;
    }
}

本地测试


/**
 * @ClAssName SwapPairs
 * @Description 两两交换链表中的节点,用递归和 while 循环轻松解决
 * @Author 欧妮甲是神仙
 * @Date 2024/6/24 19:{MINUTE}
 */
public class SwapPairs {

    public static void main(String[] args) {
        SwapPairs swapPairs = new SwapPairs();
        ListNode head = swapPairs.new ListNode(1);
        head.next  = swapPairs.new ListNode(2);
        head.next.next  = swapPairs.new ListNode(3);
        head.next.next.next  = swapPairs.new ListNode(4);
        ListNode result = swapPairs.swapPairs(head);
        while (result !=null){
            System.out.println(result.val + " ");
            result = result.next;
        }
    }
    class ListNode{
        int val;  //数据
        ListNode next;  //指针
        ListNode(){};  //空参构造
        ListNode(int val){  //数据对象
            this.val = val;
        }
        //完整的对象
        ListNode(int val , ListNode next){
            this.val=val;
            this.next = next;
        }
    }

    public  ListNode swapPairs(ListNode head){
        //1、递归终止条件:链表没有节点或只有一个节点
        if (head == null || head.next ==null){
            return head;
        }
        //2、准备交换
        //第一个节点
        ListNode firstNode = head;
        //第二个节点
        ListNode secondeNode = firstNode.next;
        //3、递归·处理后续节点  重点  =后面的处理后续节点的,比如3和4的   =前面是连接后续的节点的
        firstNode.next = swapPairs(secondeNode.next);
        //4、交换
        secondeNode.next = firstNode;
        //5、返回交换完后新的头节点
        return secondeNode;
    }

}

我们从链表的头节点 head 开始递归,每次处理一对节点,交换这对节点后,递归处理剩下的节点。

如果链表没有节点或者只有一个节点,没有交换的需要,直接返回 head。看下面这幅图就明白了。

来看题解效率:

分析 2

如果不想使用递归的话,我们也可以使用一个 while 循环来解决。

第一步,我们创建一个虚拟节点作为新链表的头节点,这可以简化边界条件的处理,虚拟节点的下一个节点指向 head。

第二步,我们开始 while 循环,条件是 head 和 head.next 都不为空。

第三步,我们使用两个临时变量来保存 head 和 head.next,然后交换这两个节点。

第四步,记得更新指针。

第五步,返回虚拟节点的下一个节点。

我们来看下面的代码:

class Solution {
    public ListNode swapPairs(ListNode head) {
        // 创建哑节点
        ListNode dummy = new ListNode(-1);
        dummy.next = head;

        ListNode prev = dummy;

        while (prev.next != null && prev.next.next != null) {
            ListNode curr = prev.next; // 当前节点
            ListNode next = curr.next; // 下一个节点

            // 交换 curr 和 next
            curr.next = next.next;
            next.next = curr;
            prev.next = next;

            // 移动指针
            prev = curr;
        }

        return dummy.next;
    }
}

简单解释下:

  • 创建一个虚拟节点 dummy,dummy 的 next 指向 head。
  • 创建一个指针 prev,指向 dummy。
  • 当 prev 的 next 和 next 的 next 都不为空时,进行交换。
  • 交换后,prev 指向 curr,curr 指向 next,next 指向 curr 的 next。
  • 返回 dummy 的 next。

因为增加了很多临时变量,所以代码没有递归简洁。

    public  ListNode swapPairsTwo(ListNode head){
        //1、创建一个虚拟的节点作为新链表的头节点,简化边界条件的处理,其下一个节点指向head
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        ListNode prev = dummy;
        //2、我们while循环 ,条件是head和head.next都不为空
        while (prev.next != null &&prev.next.next != null){
            //3、使用两个临时变量来保存head和head.next,然后交换这两个节点
            ListNode curr = prev.next;  //当前节点
            ListNode next = prev.next.next;  // 下一个节点
            //4、交换curr和next
            curr.next = next.next;
            next.next = curr;
            prev.next = next;
            //5、移动指针
            prev = curr;
        }
        //最后返回头节点
        return dummy.next;
    }

来看题解效率:

总结

其实有关链表的相关题目,最重要的切入角度,就是理清楚节点之间的关系,然后在纸上画一画,不要一个劲的只靠脑子不靠笔,往往思考了很久的问题,动动笔,就会豁然开朗,再用代码准确的描述出思路,这样子链表的问题便迎刃而解。

那这道题考察的还是链表的数据结构,以及递归和 while 循环的一些临时变量和边界条件。

力扣链接:. - 力扣(LeetCode)

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

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

相关文章

嵌入式系统中C/C++有仓颉语言对比分析

大家好,今天给大家分享一下,如何使用仓颉,以及优势在哪里? 在 2024 年 6 月 21 日的华为开发者大会上,华为不仅官宣了下一代鸿蒙操作系统 HarmonyOS NEXT,而且还正式推出了自研的编程语言 仓颉 ,可谓是赚足了面子,遥遥领先! 值得一提的是,HarmonyOS NEXT 是华为从内到…

数据库管理系统(DBMS)

一.数据库管理系统 1.简介 数据库管理系统(Database Management System)是一种操纵和管理数据库的大型软件,用于建立、使用和维护数据库,简称DBMS。它对数据库进行统一的管理和控制,以保证数据库的安全性和完整性。用户通过DBMS访问数据库中…

无线麦克风哪个品牌音质最好,一文告诉你无线领夹麦克风怎么挑选

随着直播带货和个人视频日志(Vlog)文化的兴起,以及自媒体内容创作的蓬勃发展,我们见证了麦克风行业的迅猛发展。在这一浪潮中,无线领夹麦克风以其无与伦比的便携性和操作效率,迅速赢得了广大视频制作者的喜…

WPF——属性

一、属性 类最初只有字段与函数,字段为一个变量,访问权限可以是private,protected,public。而将字段设为private,不方便外界对类数据的操作,但是将字段设为public又怕外界对数据进行非法操作,于…

【ChatBI】超轻量Python库Vanna快速上手,对接oneapi

oneapi 准备 首先确保你有oneapi ,然后申请 kimi的api 需要去Moonshot AI - 开放平台 然后添加一个api key 然后打开oneapi的渠道界面,添加kimi。 然后点击 测试, 如果能生成响应时间,就是配置正确。 然后创建令牌 http:…

探秘美食新宠:嘴尚绝卤味,口感惊艳你的味蕾!

在繁华的都市中,一道独特的卤味小吃悄然走红,它就是“嘴尚绝卤味”。今天,就让我们一起走进这家卤味店,探寻那令人回味无穷的口感秘密。 一、初识嘴尚绝卤味 “嘴尚绝”这个名字,一听就让人联想到美食的极致诱惑。店内…

从零开始构建CNN模型

猫狗分类问题——从零开始构建CNN 我们将使用相同的体系结构,并进行一些小的更改,如下所示。 第一个线性层的输入尺寸发生变化,因为猫和狗的图像尺寸是(256,256)。添加了另一个线性层来为模型学习提供更多的灵活性。 让我们来看看实现网络架…

卷积的通俗解释

以时间和空间两个维度分别理解卷积,先用文字来描述: 时间上,任何当前信号状态都是迄至当前所有信号状态的叠加;时间上,任何当前记忆状态都是迄至当前所有记忆状态的叠加;空间上,任何位置状态都…

如何将视频里的语音转成文字?5种方法轻松解决

这个信息爆炸的时代,视频内容如同潮水般涌来,而我们经常需要从这些海量的视频资源中提取关键信息。无论是为了学习、工作还是娱乐,将视频里的语音转换成文字都是一种高效的方法。这不仅可以帮助我们更好地理解内容,还能方便我们进…

【自然语言处理系列】Python 字符串操作技巧:清理、替换与合并

在编写Python程序时,字符串处理是一项常见的任务。了解如何有效地清理、修改和合并字符串对于数据预处理、文本分析和日常编程都至关重要。本文将引导您通过一系列实用的示例来掌握Python中字符串的核心操作,包括去除不需要的空格和特殊字符、替换文本中…

轻松搞定数据可视化配色,这份指南助你一臂之力!

配色是数据可视化图表的主要因素。一组合适的配色可以表达数据的重点和趋势,而不良的配色会削弱可视化表达的有效性。在本文中,我将梳理数据可视化中使用的配色板类型,通过案例揭示数据可视化配色技巧,并介绍可生成配色板的插件&a…

手撕RPC——前言

手撕RPC——前言 一、RPC是什么?二、为什么会出现RPC三、RPC的原理3.1 RPC是如何做到透明化远程服务调用?3.2 如何实现传输消息的编解码? 一、RPC是什么? RPC(Remote Procedure Call,远程过程调用&#xff…

Python笔记 文件的读取操作

1.open()打开函数 再Python,使用open函数,可以打开一个已经存在的文件,或者创建一个新文件,语法如下 open(name,mode,encoding) name:是要打开的文件名的字符串(可以包含文件所在的具体路径) mode&…

[FreeRTOS 基础知识] 信号量 概念

文章目录 信号量定义信号量特性 信号量定义 信号量是一个抽象的数据类型,通常包含一个整数值以及一个等待该值变为正数的任务列表(也称为等待队列)。信号量的整数值代表了系统中某种资源的可用数量。 在操作系统中信号量用于控制对共享资源访…

【Solr 学习笔记】Solr 源码启动教程

Solr 源码启动教程 本教程记录了如何通过 IDEA 启动并调试 Solr 源码,从 Solr9 开始 Solr 项目已由 ant 方式改成了 gradle 构建方式,本教程将以 Solr 9 为例进行演示,IDE 选择使用 IntelliJ IDEA。 Solr github 地址:https://gi…

技术干货|使用机器学习进行大数据信用评分实战演练

利用数据进行客户分类是当前金融信用风险、电商精准营销等的主流方法。那么,如何实现轻松实现客户分类呢?下面就为您介绍RapidMiner是如何快速实现客户分类的数据处理和可视化的。 例如,我们手上有某银行8000多名客户的贷款还款记录&#xff…

保姆级 | Windows 复古风格终端样式设置

0x00 前言 前段时间有朋友询问我 Windows 终端的样式是如何设置的,我也进行了一些简单的回复。在之前的 Windows 11 版本中,系统提供了一个界面按钮,可以直接将终端样式设置为复古风格。然而,系统更新之后,这个按钮好像…

对比A100和4090:两者的区别以及适用点

自2022年年末英伟达发布4090芯片以来,这款产品凭借着其优异的性能迅速在科技界占据了一席之地。现如今,不论是在游戏体验、内容创作能力方面还是模型精度提升方面,4090都是一个绕不过去的名字。而A100作为早些发布的产品,其优异的…

LLama 3的各种微调:拿我司七月的paper-review数据集微调LLama 3

前言 llama 3出来后,为了通过paper-review的数据集微调3,有以下各种方式 不用任何框架 工具 技术,直接微调原生的llama 3,毕竟也有8k长度了 效果不期望有多高,纯作为baseline通过PI,把llama 3的8K长度扩展…

标准立项 | 温室气体排放核算与报告要求 废油资源化企业

国内由于现有的废油再生企业规模较小,承担社会责任能力不强,在技术创新尤其是需要通过工程基础研究解决关键科技问题的创新积极性不高,由于经济成本的原因,多采用较落后的加工工艺,没有对废油中的特征污染物及毒害组分…