【刷题之路Ⅱ】LeetCode 143. 重排链表

news2025/4/6 16:48:43

【刷题之路Ⅱ】LeetCode 143. 重排链表

  • 一、题目描述
  • 二、解题
    • 1、方法1——线性表辅助
      • 1.1、思路分析
      • 1.2、代码实现
    • 2、方法2——中间节点+反转链表+合并链表
      • 2.1、思路分析
      • 2.2、代码实现

一、题目描述

原题连接: 143. 重排链表
题目描述:
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

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

示例 2:

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

提示:
链表的长度范围为 [1, 5 * 104]
1 <= node.val <= 1000

二、解题

1、方法1——线性表辅助

1.1、思路分析

既然链表不支持随机访问而顺序表支持随机访问,那我们就可以想办法先将链表中的节点放到一个节点数组中,然后再按题目给的顺序访问各个节点然后连接成一个新的链表即可。
当把节点存入数组中后,我们让两个指针分别指向数组的第一个元素和最后一个元素:
在这里插入图片描述
每次当我们把NodeArray[left]的next指向NodeArray[right]之后就让left向后走一步,然后再让NodeArray[right]的next指向NodeArray[left],再让right向前走一步:
在这里插入图片描述
这样就能巧妙地完成题目的要求了。
当left与right相等时我们就可以停止循环,然后将NodeArray[left]的next指向NULL即可:
在这里插入图片描述

1.2、代码实现

有了以上思路,那我们写起代码来也就水到渠成了:

void reorderList(struct ListNode* head){
    if (NULL == head || NULL == head->next) {
        return head;
    }
    struct ListNode *cur = head;
    int len = 0;
    // 先算出链表的长度
    while (cur) {
        len++;
        cur = cur->next;
    }
    // 创建一个节点数组
    struct ListNode **NodeArray = (struct ListNode**)malloc(len * sizeof(struct ListNode*));
    if (NULL == NodeArray) {
        perror("malloc fail");
        return;
    }
    cur = head;
    int n = 0;
    // 将链表中的节点拷贝到数组中
    while (cur) {
        NodeArray[n] = cur;
        n++;
        cur = cur->next;
    }
    // 完成重排
    int left = 0;
    int right = len - 1;
    while (left < right) {
        NodeArray[left]->next = NodeArray[right];
        left++;
        if (left == right) {
            break;
        }
        NodeArray[right]->next = NodeArray[left];
        right--;
    }
    NodeArray[left]->next = NULL;
}

时间复杂度:O(n),n为链表的长度。
空间复杂度:O(n),我们需要额外的n个空间来存储指向各个节点的指针。

2、方法2——中间节点+反转链表+合并链表

2.1、思路分析

通过上一方法我们其实可以发现,重排后的链表其实就是等同于前一半链表和后一半的反转后的链表合并后的结果:
在这里插入图片描述
所哟们可以先找到链表的中间节点,然后将中间节点后的链表(不包括中间节点)反转,再让原链表在中间节点处断开,然后再交叉和并这两条链表即可。
找链表的中间节点我们可以沿用[876. 链表的中间结点]中经典的快慢指针的方法。
反转链表我们可以沿用[206. 反转链表]中的头插法。

2.2、代码实现

有了以上思路,那我们写起代码来也就水到渠成了:

// 先写一个函数,找到链表的中间节点
struct ListNode* middleNode(struct ListNode* head) {
	struct ListNode* slow = head; // 慢指针,一次走一步
	struct ListNode* fast = head; // 快指针,一次走两步
	while (fast && fast->next) {
		slow = slow->next;
		fast = fast->next->next;
	}
	return slow;
}

// 再写一个函数,反转一个链表
 struct ListNode* reverseList(struct ListNode* head) {
     struct ListNode* Cur = head;
     struct ListNode* newhead = NULL; // 新的头指针
     struct ListNode* Next = NULL; // 保存cur的下一个节点,以辅助头插
     while (Cur) {
         Next = Cur->next;
         // 头插
         Cur->next = newhead;
         newhead = Cur;

         // 迭代往后走
         Cur = Next;
     }
     return newhead;
 }

void reorderList(struct ListNode* head){
    if (NULL == head || NULL == head->next) {
        return head;
    }
    // 先找到链表的中间节点
    struct ListNode *midNode = middleNode(head);

    // 再将中间节点后面的链表反转
    struct ListNode *head2 = reverseList(midNode->next);

    // 在中间节点处断开
    midNode->next = NULL;
    
    // 合并head和head2两条链表
    struct ListNode *cur1 = head;
    struct ListNode *next1 = NULL;
    struct ListNode *cur2 = head2;
    struct ListNode *next2 = NULL;
    while (cur1 && cur2) {
        next1 = cur1->next;
        next2 = cur2->next;
        cur2->next = cur1->next;
        cur1->next = cur2;
        cur1 = next1;
        cur2 = next2;
    }
}

时间复杂度:O(n),n为链表的长度。
空间复杂度:O(1),我们只需要用到常数级的额外空间。

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

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

相关文章

7. Docker——Dockerfile

本章讲解知识点 DockerfileDockerfile 常用命令Dockerfile 综合示例Docker Compose当我们理解了镜像的基本原理后,我们就可以开始 Dockerfile 的学习了。 1. Dockerfile Dockerfile 是用于构建 Docker 镜像的脚本。它包含一组指令,按顺序执行以创建 Docker 镜像,从而使其可…

多通道振弦传感器无线采集仪通过短信和FTP文件修改参数

多通道振弦传感器无线采集仪通过短信和FTP文件修改参数 通过短信修改参数 向设备发送参数修改指令&#xff0c;设备在下次采发过程中若收到包含有合法指令的短信时会解析并执行短信内的指令&#xff0c;参数修改完成后会以短信形式回发应答信息。短信指令的格式如下&#xff1a…

ChatGPT实现仪表盘生成

仪表盘生成 Grafana是开源社区最流行的数据可视化软件&#xff0c;一定程度上也和 superset 一起被视为 tableau 等商业 BI 的开源替代品&#xff0c;很多IT 团队、科研团队&#xff0c;都会使用 Grafana 来做数据监控、挖掘分析。Grafana社区也有很多贡献者&#xff0c;在 gi…

设计模式-基本概念

设计模式-基本概念 基本概念奇异递归模板模式&#xff08;CRTP&#xff09;说明示例例子1&#xff1a;对象计数例子2&#xff1a;多态复制构造例子4&#xff1a;std::enable_shared_from_this例子5 树简单遍历 混合继承属性SOLID 设计原则 参考 基本概念 奇异递归模板模式&…

带你彻底理解Spark的分区

前言 我&#xff1a;什么是RDD&#xff1f; 面试者&#xff1a;RDD是被分区的&#xff0c;由一系列分区组成… … 我&#xff1a;你怎么理解分区&#xff1f; 面试者&#xff1a;… 我&#xff1a;Spark中有哪些可以实现分区的方法&#xff1f;分别使用的场景是什么&#xff1…

nodejs-前端工程化环境-安装-webpack打包工具

文章目录 1.安装nodejs1.1.新建项目1.2.安装jQuery。1.3.查看全局模块安装目录 2.安装Vue2.1.安装2.2.创建vue项目 3.安装webpack4.安装 Grunt5.安装uglify-js > js代码压缩打包工具。6.因为在此系统上禁止运行脚本……解决办法 1.安装nodejs 从官网下载长期支持版本&#…

数值分析-埃尔米特插值的概念、实现与应用

目录 一、引言 二、埃尔米特插值的基本概念 2.1 埃尔米特插值的定义 2.2 埃尔米特插值的优点 三、埃尔米特插值的实现方法 3.1 基于拉格朗日插值的埃尔米特插值 2.2 基于牛顿插值的埃尔米特插值 四、埃尔米特插值的应用 4.1 基于埃尔米特插值的函数逼近 4.2 基于埃尔…

2分钟搞懂人工智能、机器学习和深度学习

不少高校的小伙伴找我聊入门人工智能该怎么起步&#xff0c;如何快速入门&#xff0c;多长时间能成长为中高级工程师&#xff08;聊下来感觉大多数学生党就是焦虑&#xff0c;毕业即失业&#xff0c;尤其现在就业环境这么差&#xff09;&#xff0c;但聊到最后&#xff0c;很多…

java遍历集合的方法

java中&#xff0c;集合的遍历是一项基本且重要的技能。我们不仅要知道集合中元素的个数&#xff0c;还要知道元素的值&#xff0c;以及它们之间的关系。 在 Java中&#xff0c;如果需要遍历集合中的某个元素&#xff0c;可以使用以下方法&#xff1a; 1.通过 return语句将集合…

工赋开发者社区 | 装备制造企业数字化转型总体框架

导读 当前&#xff0c;面对技术、市场以及供应链等多重挑战&#xff0c;在软件定义、数据驱动、数字孪生、大数据、人工智能及元宇宙等技术加持下&#xff0c;装备制造企业不断采用新工艺、新材料&#xff0c;以新模式推动产品快速创新。企业积极关注并探索数字化转型路径&…

ThingsBoard使用docker compose集群部署

1、概述 今天我将讲解官方文档说的使用docker compose集群部署ThingsBoard,这种部署方式也是目前企业中常用的形式,希望大家能够掌握,我不是直接使用官方的镜像,我是自己拉起代码,然后自己构建镜像,在传到服务器上,使用自己的镜像来部署。而且这种部署中间有个大坑,我…

雷达原理_有源干扰_间歇采样直接、重复、循环转发干扰_含MATLAB实现代码

间歇采样直接、重复、循环转发干扰 间歇采样转发干扰是在雷达脉冲周期内对雷达信号进行间歇采样&#xff0c;并通过干扰机将采样的信号进行处理和转发&#xff0c;从而生成相干的假目标信号。这种干扰方式的原理可分为直接转发、重复转发和逐次循环转发三种方式。直接转发是指…

这个档案室管理妙招,太有用了!

档案是人类文明发展到一定历史阶段的产物&#xff0c;是人类活动的真实记录&#xff0c;也是新的社会实践最可靠的凭证和依据。 借助档案&#xff0c;我们能够更好地了解过去、把握现在、预见未来&#xff0c;是一种宝贵的无形资产&#xff0c;也是一种不可再生资源。因此&…

Pandas + AI = PandasAI【Python】

Pandas AI 是一个 Python 库&#xff0c;它为流行的数据分析和操作工具 Pandas 添加了生成式AI能力。 PandasAI旨在与 Pandas 结合使用&#xff0c;而不是它的替代品。 推荐&#xff1a;用 NSDT场景设计器 快速搭建3D场景 1、安装PandasAI 使用如下命令安装pandas-ai&#xf…

linux中TF启动卡制作:磁盘分区文件同步

文章目录 前言&#xff1a;1. 连接TF卡2. 磁盘卸载载与分区2.1 磁盘卸载2.2 创建第一个分区2.3 创建第二个分区 3. 磁盘格式化4. 文件同步5. 检查与BOOT分区启动文件拷贝总结&#xff1a; 前言&#xff1a; TF卡在linux环境下配置好相关软件后&#xff0c;把配置好的系统以及软…

Neo4j图数据库的数据模型_包括节点_属性_数据_关系---Neo4j图数据库工作笔记0002

来看一下neo4j的特性 这个neo4j特点就是简单,这里用最快的速度学习 可以看到一个圈表示一个节点,然后两个节点直接可以有关系,关系可以是双向的

Python正则表达式详解,保姆式教学,0基础也能掌握正则

正则作为处理字符串的一个实用工具&#xff0c;在Python中经常会用到&#xff0c;比如爬虫爬取数据时常用正则来检索字符串等等。正则表达式已经内嵌在Python中&#xff0c;通过导入re模块就可以使用&#xff0c;作为刚学Python的新手大多数都听说”正则“这个术语。 今天来给…

学生成绩管理系统【纯控制台】(Java课设)

系统类型 纯控制台类型&#xff08;没有用到数据库&#xff09; 使用范围 适合作为Java课设&#xff01;&#xff01;&#xff01; 部署环境 jdk1.8Idea或eclipse 运行效果 本系统源码地址&#xff1a;https://download.csdn.net/download/qq_50954361/87753365 更多系统…

Python每日一练(20230505) 课程表 Course Schedule III/IV

目录 3. 课程表 Course Schedule III 4. 课程表 Course Schedule IV &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 3. 课程表 Course Schedule III 这里有 n 门不同的在线课程&#xff…

python并发编程:什么是并发编程?python对并发编程有哪些支持?

Python并发编程是指同时执行多个任务的编程模式。Python提供了多种实现并发编程的方式&#xff0c;包括多线程、多进程、协程、异步IO等。 为什么要引入并发编程 假设以下两个场景&#xff1a; 场景一: 一个网络爬虫&#xff0c;按顺序爬取花了一个小时&#xff0c;采用并发…