LeetCode hot 力扣热题100 排序链表

news2025/1/22 2:11:16

归并忘了 直接抄!

class Solution { // 定义一个 Solution 类,包含链表排序的相关方法。
    // 使用快慢指针找到链表的中间节点,并断开链表为两部分
    ListNode* middleNode(ListNode* head) { 
        ListNode* slow = head; // 慢指针 slow 初始化为链表头节点
        ListNode* fast = head; // 快指针 fast 初始化为链表头节点
        while (fast->next && fast->next->next) { // 当 fast 指针还能向前走两步时循环
            slow = slow->next; // slow 每次向前移动一步
            fast = fast->next->next; // fast 每次向前移动两步
        }
        ListNode* mid = slow->next; // 找到中间节点的下一节点,将其作为右半部分的头节点
        slow->next = nullptr; // 将左半部分的最后一个节点的 next 指针置为 nullptr,断开链表
        return mid; // 返回右半部分的头节点 mid
    }

    // 合并两个有序链表,返回合并后的链表头节点
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        ListNode dummy; // 定义一个哨兵节点,简化合并逻辑
        ListNode* cur = &dummy; // cur 用于构建新链表,初始指向哨兵节点
        while (list1 && list2) { // 当两个链表都不为空时进行合并
            if (list1->val < list2->val) { // 如果 list1 的当前值小于 list2 的当前值
                cur->next = list1; // 将 list1 的节点加入新链表
                list1 = list1->next; // list1 指针向后移动
            } else { // 否则,将 list2 的节点加入新链表
                cur->next = list2;
                list2 = list2->next; // list2 指针向后移动
            }
            cur = cur->next; // cur 指针向后移动
        }
        cur->next = list1 ? list1 : list2; // 将剩余的非空链表直接接到新链表末尾
        return dummy.next; // 返回新链表的头节点(哨兵节点的下一个节点)
    }

public:
    // 链表归并排序的主函数
    ListNode* sortList(ListNode* head) {
        if (head == nullptr || head->next == nullptr) { // 如果链表为空或只有一个节点,直接返回
            return head;
        }
        ListNode* head2 = middleNode(head); // 使用 middleNode 函数分割链表,head2 是右半部分的头节点
        head = sortList(head); // 递归地对左半部分链表排序
        head2 = sortList(head2); // 递归地对右半部分链表排序
        return mergeTwoLists(head, head2); // 将两个有序链表合并为一个
    }
};

思路详解

这段代码实现了 归并排序(Merge Sort)在链表上的应用,通过递归的方式将链表分割成两个部分,然后排序并合并。

核心思路

1. 拆分链表

使用快慢指针(middleNode 函数)找到链表的中间节点,将链表拆分为两部分。

2. 递归排序

对拆分后的两部分链表分别递归调用 sortList,直到链表被拆分为单个节点(此时链表自然是有序的)。

3. 合并链表

使用双指针(mergeTwoLists 函数)将两个有序链表合并为一个有序链表。

代码分析

1. middleNode 函数(找到中间节点并断开链表)

ListNode* middleNode(ListNode* head) {

    ListNode* slow = head;

    ListNode* fast = head;

    while (fast->next && fast->next->next) {

        slow = slow->next;

        fast = fast->next->next;

    }

    ListNode* mid = slow->next; // 中间节点

    slow->next = nullptr;       // 断开链表

    return mid;

}

功能:找到链表的中间节点并断开链表。

原理:使用快慢指针:

• 快指针 fast 每次移动两步;

• 慢指针 slow 每次移动一步;

• 当 fast 到达链表末尾时,slow 指向链表的中间节点。

返回值:mid 是中间节点的指针,用于分割链表。

2. mergeTwoLists 函数(合并两个有序链表)

ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {

    ListNode dummy; // 哨兵节点,简化合并过程

    ListNode* cur = &dummy;

    while (list1 && list2) {

        if (list1->val < list2->val) {

            cur->next = list1;

            list1 = list1->next;

        } else {

            cur->next = list2;

            list2 = list2->next;

        }

        cur = cur->next;

    }

    cur->next = list1 ? list1 : list2; // 拼接剩余链表

    return dummy.next; // 返回合并后的链表

}

功能:将两个有序链表合并为一个有序链表。

原理:使用双指针逐个比较两个链表的节点值,将较小值的节点连接到新链表上,直到其中一个链表为空。

返回值:合并后的链表头指针。

3. sortList 函数(链表归并排序的入口)

ListNode* sortList(ListNode* head) {

    if (head == nullptr || head->next == nullptr) {

        return head; // 链表为空或只有一个节点,无需排序

    }

    ListNode* head2 = middleNode(head); // 分割链表

    head = sortList(head);              // 递归排序左部分

    head2 = sortList(head2);            // 递归排序右部分

    return mergeTwoLists(head, head2);  // 合并两个有序链表

}

功能:实现链表的归并排序。

分割链表

• 调用 middleNode 函数找到链表的中间节点,并将链表分为两部分。

• 比如 [4,2,1,3] 分为 [4,2] 和 [1,3]。

递归排序

• 递归地对两部分链表分别调用 sortList 进行排序。

• 递归终止条件是链表为空或只有一个节点。

合并链表

• 调用 mergeTwoLists 函数将两个有序链表合并为一个。

算法过程

递归是一种通过函数调用自身来解决问题的方式,它通常分为两部分:终止条件递推关系。每一层递归会在满足特定条件后返回结果,并将结果传递给上一层递归调用。下面以链表排序 sortList 函数为例,详细说明递归的每一层操作。

每一层递归如何工作

以链表 [4, 2, 1, 3] 为例,说明每一层递归的处理过程。

第 1 层递归

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

中间节点:middleNode 找到 mid = 1,链表被分为两部分:

• head = [4, 2]

• head2 = [1, 3]

递归调用

• 对 [4, 2] 和 [1, 3] 分别调用 sortList。

第 2 层递归

左侧递归

• 输入:head = [4, 2]

中间节点:mid = 2,链表分为:

• head = [4]

• head2 = [2]

递归调用

• 对 [4] 和 [2] 调用 sortList。

合并结果

• mergeTwoLists([4], [2]) 返回 [2, 4]。

右侧递归

• 输入:head = [1, 3]

中间节点:mid = 3,链表分为:

• head = [1]

• head2 = [3]

递归调用

• 对 [1] 和 [3] 调用 sortList。

合并结果

• mergeTwoLists([1], [3]) 返回 [1, 3]。

第 3 层递归

输入

• [4] 和 [2]:直接返回,因为链表只有一个节点或为空。

• [1] 和 [3]:同样直接返回。

回溯过程

第 2 层返回

• 左侧 [4, 2] 合并为 [2, 4]。

• 右侧 [1, 3] 合并为 [1, 3]。

第 1 层合并

• mergeTwoLists([2, 4], [1, 3]) 返回 [1, 2, 3, 4]。

总结

• 每层递归处理的是将链表分为两部分,并对每部分递归调用 sortList。

• 在回溯时,通过 mergeTwoLists 合并两个有序链表。

递归终止条件:链表为空或只有一个节点时,直接返回。

递归的深度:链表长度为 ,递归深度为 。

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

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

相关文章

JavaScript正则表达式解析:模式、方法与实战案例

目录 一、什么是正则表达式 1.创建正则表达式 2.标志&#xff08;Flags&#xff09; 3.基本模式 &#xff08;1&#xff09;字符匹配 &#xff08;2&#xff09;位置匹配 &#xff08;3&#xff09;数量匹配 二、常用的正则表达式方法和属性 1.test()‌ 2.match()‌ …

Nginx在Linux中的最小化安装方式

1. 安装依赖 需要安装的东西&#xff1a; wget​&#xff0c;方便我们下载Nginx的包。如果是在Windows下载&#xff0c;然后使用SFTP上传到服务器中&#xff0c;那么可以不安装这个软件包。gcc g​&#xff0c;Nginx是使用C/C开发的服务器&#xff0c;等一下安装会用到其中的…

【大模型】ChatGPT 高效处理图片技巧使用详解

目录 一、前言 二、ChatGPT 4 图片处理介绍 2.1 ChatGPT 4 图片处理概述 2.1.1 图像识别与分类 2.1.2 图像搜索 2.1.3 图像生成 2.1.4 多模态理解 2.1.5 细粒度图像识别 2.1.6 生成式图像任务处理 2.1.7 图像与文本互动 2.2 ChatGPT 4 图片处理应用场景 三、文生图操…

基于python+Django+mysql鲜花水果销售商城网站系统设计与实现

博主介绍&#xff1a;黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者&#xff0c;CSDN博客专家&#xff0c;在线教育专家&#xff0c;CSDN钻石讲师&#xff1b;专注大学生毕业设计教育、辅导。 所有项目都配有从入门到精通的基础知识视频课程&#xff…

-bash: /java: cannot execute binary file

在linux安装jdk报错 -bash: /java: cannot execute binary file 原因是jdk安装包和linux的不一致 程序员的面试宝典&#xff0c;一个免费的刷题平台

免费为企业IT规划WSUS:Windows Server 更新服务 (WSUS) 之快速入门教程(一)

哈喽大家好&#xff0c;欢迎来到虚拟化时代君&#xff08;XNHCYL&#xff09;&#xff0c;收不到通知请将我点击星标&#xff01;“ 大家好&#xff0c;我是虚拟化时代君&#xff0c;一位潜心于互联网的技术宅男。这里每天为你分享各种你感兴趣的技术、教程、软件、资源、福利…

面试--你的数据库中密码是如何存储的?

文章目录 三种分类使用 MD5 加密存储加盐存储Base64 编码:常见的对称加密算法常见的非对称加密算法https 传输加密 在开发中需要存储用户的密码&#xff0c;这个密码一定是加密存储的&#xff0c;如果是明文存储那么如果数据库被攻击了&#xff0c;密码就泄露了。 我们要对数据…

模型部署工具01:Docker || 用Docker打包模型 Build Once Run Anywhere

Docker 是一个开源的容器化平台&#xff0c;可以让开发者和运维人员轻松构建、发布和运行应用程序。Docker 的核心概念是通过容器技术隔离应用及其依赖项&#xff0c;使得软件在不同的环境中运行时具有一致性。无论是开发环境、测试环境&#xff0c;还是生产环境&#xff0c;Do…

Restormer: Efficient Transformer for High-Resolution Image Restoration解读

论文地址&#xff1a;Restormer: Efficient Transformer for High-Resolution Image Restoration。 摘要 由于卷积神经网络&#xff08;CNN&#xff09;在从大规模数据中学习可推广的图像先验方面表现出色&#xff0c;这些模型已被广泛应用于图像复原及相关任务。近年来&…

四、CSS效果

一、box-shadow box-shadow:在元素的框架上添加阴影效果 /* x 偏移量 | y 偏移量 | 阴影颜色 */ box-shadow: 60px -16px teal; /* x 偏移量 | y 偏移量 | 阴影模糊半径 | 阴影颜色 */ box-shadow: 10px 5px 5px black; /* x 偏移量 | y 偏移量 | 阴影模糊半径 | 阴影扩散半…

火狐浏览器Firefox一些配置

没想到还会开这个…都是Ubuntu的错 一些个人习惯吧 标签页设置 常规-标签页 1.按最近使用顺序切换标签页 2.打开新标签而非新窗口&#xff08;讨厌好多窗口&#xff09; 3.打开新链接不直接切换过去&#xff08;很打断思路诶&#xff09; 4.关闭多个标签页时不向我确认 启动…

MECD+: 视频推理中事件级因果图推理--VLM长视频因果推理

论文链接&#xff1a;https://arxiv.org/pdf/2501.07227v1 1. 摘要及主要贡献点 摘要&#xff1a; 视频因果推理旨在从因果角度对视频内容进行高层次的理解。然而&#xff0c;目前的研究存在局限性&#xff0c;主要表现为以问答范式执行&#xff0c;关注包含孤立事件和基本因…

Python基于Django的社区爱心养老管理系统设计与实现【附源码】

博主介绍&#xff1a;✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&…

Docker 单机快速部署大数据各组件

文章目录 一、Spark1.1 NetWork 网络1.2 安装 Java81.3 安装 Python 环境1.4 Spark 安装部署 二、Kafka三、StarRocks四、Redis五、Rabbitmq六、Emqx6.1 前言6.2 安装部署 七、Flink八、Nacos九、Nginx 一、Spark 1.1 NetWork 网络 docker network lsdocker network create -…

【MySQL】:Linux 环境下 MySQL 使用全攻略

&#x1f4c3;个人主页&#xff1a;island1314 &#x1f525;个人专栏&#xff1a;MySQL学习 ⛺️ 欢迎关注&#xff1a;&#x1f44d;点赞 &#x1f442;&#x1f3fd;留言 &#x1f60d;收藏 &#x1f49e; &#x1f49e; &#x1f49e; 1. 背景 &#x1f680; 世界上主…

【思科】NAT配置

网络拓扑图 这个网络拓扑的核心是Router1&#xff0c;它通过配置多个VLAN子接口来实现对不同VLAN的支持&#xff0c;并通过NAT进行地址转换&#xff0c;使得内部网络能够与外部网络进行通信。Router1上配置了FastEthernet0/0.x接口&#xff0c;并启用了802.1Q封装&#xff0c;…

WGAN - 瓦萨斯坦生成对抗网络

1. 背景与问题 生成对抗网络&#xff08;Generative Adversarial Networks, GANs&#xff09;是由Ian Goodfellow等人于2014年提出的一种深度学习模型。它包括两个主要部分&#xff1a;生成器&#xff08;Generator&#xff09;和判别器&#xff08;Discriminator&#xff09;…

【数学建模美赛速成系列】O奖论文绘图复现代码

文章目录 引言折线图 带误差棒得折线图单个带误差棒得折线图立体饼图完整复现代码 引言 美赛的绘图是非常重要得&#xff0c;这篇文章给大家分享我自己复现2024年美赛O奖优秀论文得代码&#xff0c;基于Matalab来实现&#xff0c;可以直接运行出图。 折线图 % MATLAB 官方整理…

兼职全职招聘系统架构与功能分析

2015工作至今&#xff0c;10年资深全栈工程师&#xff0c;CTO&#xff0c;擅长带团队、攻克各种技术难题、研发各类软件产品&#xff0c;我的代码态度&#xff1a;代码虐我千百遍&#xff0c;我待代码如初恋&#xff0c;我的工作态度&#xff1a;极致&#xff0c;责任&#xff…

svn tag

一般发布版本前&#xff0c;需要在svn上打个tag。步骤如下&#xff1a; 1、空白处右击&#xff0c;选择TortoiseSVN->Branch/tag; 2、填写To path&#xff0c;即tag的路基以及tag命名&#xff08;一般用版本号来命名&#xff09;&#xff1b;填写tag信息&#xff1b;勾选cr…