python-leetcode 33.排序链表

题目:

给定链表的头结点head,请将其按升序排列,并返回排序后的链表


方法一:自顶向下归并排序

链表自顶向下归并排序的过程:

1.找到链表的中点,以中点为分界,将链表拆分成两个子链表。寻找链表的中点可以使用快慢指针的做法,快指针每次移动 2 步,慢指针每次移动 1 步,当快指针到达链表末尾时,慢指针指向的链表节点即为链表的中点

2.对两个链表进行排序

3.将两个排序后的子链表合并,得到完整的排序后的链表。可以使用[合并两个有序链表]的做法,将两个有序的子链表进行合并

可以通过递归实现。递归的终止条件是链表的节点个数小于或等于 1,即当链表为空或者链表只包含 1 个节点时,不需要对链表进行拆分和排序

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):def sortList(self, head):""":type head: Optional[ListNode]:rtype: Optional[ListNode]"""def sortFunc(head,tail):#个递归的排序函数,tail 是递归调用时用于控制链表的尾部的边界if not head: #链表已经空return headif head.next==tail: #当前链表只有一个元素,或者已经到达分割链表的边界head.next=Nonereturn headslow=fast=headwhile fast !=tail:slow=slow.nextfast=fast.nextif fast != tail:  #fast 每次走两步,slow 每次走一步fast=fast.nextmid=slow  #当 fast 到达链表尾部时,slow 就在链表的中间位置return merge(sortFunc(head,mid),sortFunc(mid,tail))
#递归调用sortFunc对head到mid的部分和mid到tail的部分分别进行排序,然后将两个排序好的部分合并。合并的过程交给 merge 函数def merge(head1,head2): #将两个已排序的链表合并成一个有序的链表dummyHead=ListNode(0) #虚拟的头节点temp,temp1,temp2=dummyHead,head1,head2
#临时指针,用来构建最终合并的链表,两个已排序链表的头节点while temp1 and temp2: #同时遍历temp1和temp2,比较它们的值,并将较小的节点连接到 temp 上,直到其中一个链表遍历完if temp1.val<temp2.val:temp.next=temp1  #将 temp1 加入合并后的链表temp1=temp1.next #将 temp1 移动到下一个节点else:temp.next=temp2temp2=temp2.nexttemp=temp.next  #将已合并链表的指针后移if temp1:  #如果 temp1 链表剩余节点未合并完,则直接将剩余的节点连接temp.next=temp1elif temp2:  #如果 temp2 链表剩余节点未合并完,同样将剩余的节点连接到temp.next=temp2return dummyHead.next  #去除虚拟结点,返回合并后的链表的头节点return sortFunc(head,None) #sortList 函数通过调用 sortFunc 来对整个链表进行排序,None 作为 tail 的参数表示没有上限

时间复杂度:O(nlogn)

空间复杂度:O(nlogn)


方法二:自底向上归并排序

首先求得链表的长度 length,然后将链表拆分成子链表进行合并。

具体做法:

  1. 用 subLength 表示每次需要排序的子链表的长度,初始时 subLength=1。

  2. 每次将链表拆分成若干个长度为 subLength 的子链表(最后一个子链表的长度可以小于 subLength)按照每两个子链表一组进行合并,合并后即可得到若干个长度为subLength×2 的有序子链表(最后一个子链表的长度可以小于 subLength×2)。合并两个子链表仍然使用[合并两个有序链表]的做法。

  3. 将 subLength 的值加倍,重复第 2 步,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于 length,整个链表排序完毕。        

举例: 

首先,归并长度为 1 的子链表。例如 [4,2,1,3],把第一个节点和第二个节点归并,第三个节点和第四个节点归并,得到 [2,4,1,3]。
然后,归并长度为 2 的子链表。例如 [2,4,1,3],把前两个节点和后两个节点归并,得到 [1,2,3,4]。
然后,归并长度为 4 的子链表。
依此类推,直到归并的长度大于等于链表长度为止,此时链表已经是有序的了。

初始链表: 4 -> 2 -> 1 -> 3

step = 1:
- 分割: [4], [2], [1], [3]
- 合并: [2 -> 4], [1 -> 3]
- 结果: 2 -> 4 -> 1 -> 3

step = 2:
- 分割: [2 -> 4], [1 -> 3]
- 合并: [1 -> 2 -> 3 -> 4]
- 结果: 1 -> 2 -> 3 -> 4

step = 4:
- 分割: [1 -> 2 -> 3 -> 4]
- 无需合并
- 结果: 1 -> 2 -> 3 -> 4

最终结果: 1 -> 2 -> 3 -> 4

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = nextclass Solution(object):# 获取链表长度def getListLength(self, head):length = 0while head:length += 1head = head.nextreturn length# 分割链表# 如果链表长度 <= size,不做任何操作,返回空节点# 如果链表长度 > size,把链表的前 size 个节点分割出来(断开连接),并返回剩余链表的头节点def splitList(self, head, size):# 先找到 next_head 的前一个节点cur = headfor _ in range(size - 1):if cur is None:breakcur = cur.next# 如果链表长度 <= sizeif cur is None or cur.next is None:return None  # 不做任何操作,返回空节点next_head = cur.nextcur.next = None  # 断开 next_head 的前一个节点和 next_head 的连接return next_head# 合并两个有序链表(双指针)# 返回合并后的链表的头节点和尾节点def mergeTwoLists(self, list1, list2):cur = dummy = ListNode()  # 用哨兵节点简化代码逻辑while list1 and list2:if list1.val < list2.val:cur.next = list1  # 把 list1 加到新链表中list1 = list1.nextelse:  # 注:相等的情况加哪个节点都是可以的cur.next = list2  # 把 list2 加到新链表中list2 = list2.nextcur = cur.nextif list1:cur.next=list1elif list2:cur.next=list2while cur.next:cur=cur.nextreturn dummy.next, curdef sortList(self, head):length = self.getListLength(head)  # 获取链表长度dummy = ListNode(next=head)  # 用哨兵节点简化代码逻辑step = 1  # 步长(参与合并的链表长度)while step < length:new_list_tail = dummy  # 新链表的末尾cur = dummy.next  # 每轮循环的起始节点while cur:# 从 cur 开始,分割出两段长为 step 的链表,头节点分别为 head1 和 head2head1 = curhead2 = self.splitList(head1, step)cur = self.splitList(head2, step)  # 下一轮循环的起始节点# 合并两段长为 step 的链表head, tail = self.mergeTwoLists(head1, head2)# 合并后的头节点 head,插到 new_list_tail 的后面new_list_tail.next = headnew_list_tail = tail  # tail 现在是新链表的末尾step *= 2return dummy.next

时间复杂度:O(logn) 

空间复杂度:O(1)

方法一的归并是自顶向下计算,需要 O(logn) 的递归栈开销。

方法二将其改成自底向上计算,空间复杂度优化成 O(1)

                                                                                                        源自力扣官方题解,灵茶山艾府
 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PyQt加载UI文件

1.动态加载 import sys from PySide6 import QtCore,QtWidgets from PySide6.QtWidgets import * from PySide6.QtUiTools import QUiLoaderclass readfile(QWidget):def __init__(self):super().__init__()self.uiQUiLoader().load("test.ui",self) self.__c…

深入解析NoSQL数据库:从文档存储到图数据库的全场景实践

title: 深入解析NoSQL数据库:从文档存储到图数据库的全场景实践 date: 2025/2/19 updated: 2025/2/19 author: cmdragon excerpt: 通过电商、社交网络、物联网等12个行业场景,结合MongoDB聚合管道、Redis Stream实时处理、Cassandra SSTable存储引擎、Neo4j路径遍历算法等42…

EasyRTC:开启智能硬件与全平台互动新时代

在当今数字化时代&#xff0c;实时音视频互动已成为企业与用户沟通、协作和娱乐的关键技术。无论是在线教育、视频会议、远程医疗还是互动直播&#xff0c;流畅、高效的互动体验都是成功的关键。然而&#xff0c;实现跨平台、低延迟且功能丰富的音视频互动并非易事——直到 Eas…

【前端框架】vue2和vue3的区别详细介绍

Vue 3 作为 Vue 2 的迭代版本&#xff0c;在性能、语法、架构设计等多个维度均有显著的变革与优化。以下详细剖析二者的区别&#xff1a; 响应式系统 Vue 2 实现原理&#xff1a;基于 Object.defineProperty() 方法实现响应式。当一个 Vue 实例创建时&#xff0c;Vue 会遍历…

springboot-ffmpeg-m3u8-convertor nplayer视频播放弹幕 artplayer视频弹幕

学习链接 ffmpeg-cli-wrapper - 内部封装了操作ffmpeg命令的java类库&#xff0c;它提供了一些类和方法&#xff0c;可以方便地构建和执行 ffmpeg 命令&#xff0c;而不需要直接操作字符串或进程。并且支持异步执行和进度监听 springboot-ffmpeg-m3u8-convertor - gitee代码 …

Linux下centos系统中使用docker容器中的ollama下载deepseek速度太慢解决办法

以下是使用shell脚本实现的一个示例&#xff0c;该脚本会尝试下载一个名为"deepseek-r1:32b"的模型。通过每隔60秒中断一次下载操作&#xff0c;从何恢复下载速度。亲测有效,其中需要将模型改为你自己要下载的模型 #!/bin/bashwhile true; do# 检查模型是否已下载完…

自动创建spring boot应用(eclipse版本)

使用spring starter project创建项目 设置Service URL 把Service URL设置为 https://start.aliyun.com/ 如下图&#xff1a; 使用这个网址&#xff0c;创建项目更快。 选择Spring Web依赖 项目结构 mvnw和mvnw.cmd:这是maven包装器&#xff08;wrapper&#xff09;脚本&…

基于flask+vue的租房信息可视化系统

✔️本项目利用 python 网络爬虫抓取某租房网站的租房信息&#xff0c;完成数据清洗和结构化&#xff0c;存储到数据库中&#xff0c;搭建web系统对各个市区的租金、房源信息进行展示&#xff0c;根据各种条件对租金进行预测。 1、数据概览 ​ 将爬取到的数据进行展示&#xff…

uniapp 滚动尺

scale组件代码&#xff08;部分class样式使用到了uview1.0的样式&#xff09; <template><view><view class"scale"><view class"pointer u-flex-col u-col-center"><u-icon name"arrow-down-fill" size"26&qu…

分布式大语言模型服务引擎vLLM论文解读

论文地址&#xff1a;Efficient Memory Management for Large Language Model Serving with PagedAttention 摘要 大语言模型&#xff08;LLMs&#xff09;的高吞吐量服务需要一次对足够多的请求进行批处理。然而&#xff0c;现有系统面临困境&#xff0c;因为每个请求的键值…

【HeadFirst系列之HeadFirst设计模式】第5天之工厂模式:比萨店的秘密武器,轻松搞定对象创建!

工厂模式&#xff1a;比萨店的秘密武器&#xff0c;轻松搞定对象创建&#xff01; 大家好&#xff0c;今天我们来聊聊设计模式中的工厂模式。如果你曾经为对象的创建感到头疼&#xff0c;或者觉得代码中到处都是 new 关键字&#xff0c;那么工厂模式就是你的救星&#xff01;本…

CSS基本选择器

1. 通配选择器 作用&#xff1a;可以选中所有的 HTML 元素。 语法&#xff1a; * { 属性名: 属性值; } 举例&#xff1a; <!DOCTYPE html> <html lang"zh-cn"> <head><meta charset"UTF-8"><meta name"viewport" …

Idea24.3 如何设置Git忽略某一个文件

文章目录 左上角找到commit选中你要忽略的文件 右键New Changelist给这个文件夹名称和描述 点击ok将要忽略的文件添加到这个文件夹 左上角找到commit 选中你要忽略的文件 右键New Changelist 给这个文件夹名称和描述 点击ok 将要忽略的文件添加到这个文件夹

ctfshow web入门 web11-web24

web11 web12 进来浏览网站&#xff0c;底部有一串数字&#xff0c;根据提示可能有用&#xff0c;访问robots.txt&#xff0c;发现禁止访问/admin/&#xff0c;进去看看发现需要输入用户名和密码&#xff0c;刚想爆破就猜对了&#xff0c;用户名是admin&#xff0c;密码是页面下…

MySQL笔记-对max_allowed_packet的进一步理解(2024-10-28)

背景 最近不仅仅在做开发&#xff0c;还在不停的做实施&#xff0c;运维。以前都不太喜欢做实施&#xff0c;运维&#xff0c;但是工作6年后&#xff0c;对这些还是比较感兴趣了&#xff0c;毕竟计算机这块不仅仅是开发&#xff0c;还有很多岗位&#xff0c;并且实施和运维会从…

Elasticsearch:探索 CLIP 替代方案

作者&#xff1a;来自 Elastic Jeffrey Rengifo 及 Toms Mura 分析图像到图像和文本到图像搜索的 CLIP 模型的替代方案。 在本文中&#xff0c;我们将通过一个模拟房地产网站的实际示例介绍 CLIP 多模态模型&#xff0c;探索替代方案&#xff0c;并分析它们的优缺点&#xff0c…

Spring中的日志

日志 了解一下 (有个印象) 门面模式 (外观模式) 含有两种角色&#xff1a; Facade (外观角色 / 门面角色): 系统对外的统一接口。SubSystem (子系统角色): 可以含有多个子系统&#xff0c;每个子系统都不是单独的类&#xff0c;而是一个类的集合。 Facade 对 SubSystem 是…

uniapp邪门事件

很久之前在这篇《THREEJS 在 uni-app 中使用&#xff08;微信小程序&#xff09;》&#xff1a;THREEJS 在 uni-app 中使用&#xff08;微信小程序&#xff09;_uni-app_帶刺的小葡萄-华为开发者空间 中学到了如何在uniapp的微信小程序里接入three.js的3d模型 由于小程序自身很…

C#项目04——递归求和

实现逻辑 利用递归&#xff0c;求取1~N以内的和 知识点 正常情况下&#xff0c;C#每条线程都会分配1MB的地址空间&#xff0c;因此执行递归的层次不能太深&#xff0c;否则就会出现溢出的风险&#xff0c; 业务设计 程序代码 private void button1_Click(object sender, E…

SQLMesh 系列教程6- 详解 Python 模型

本文将介绍 SQLMesh 的 Python 模型&#xff0c;探讨其定义、优势及在企业业务场景中的应用。SQLMesh 不仅支持 SQL 模型&#xff0c;还允许通过 Python 编写数据模型&#xff0c;提供更高的灵活性和可编程性。我们将通过一个电商平台的实例&#xff0c;展示如何使用 Python 模…