Python算法题集_随机链表的复制

 Python算法题集_随机链表的复制

  • 题138:随机链表的复制
  • 1. 示例说明
  • 2. 题目解析
    • - 题意分解
    • - 优化思路
    • - 测量工具
  • 3. 代码展开
    • 1) 标准求解【双层循环】
    • 2) 改进版一【字典哈希】
    • 3) 改进版二【单层哈希】
    • 4) 改进版三【递归大法】
  • 4. 最优算法

本文为Python算法题集之一的代码示例

题138:随机链表的复制

1. 示例说明

  • 给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

    构造这个链表的 深拷贝。 深拷贝应该正好由 n全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点

    例如,如果原链表中有 XY 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 xy ,同样有 x.random --> y

    返回复制链表的头节点。

    用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

    • val:一个表示 Node.val 的整数。
    • random_index:随机指针指向的节点索引(范围从 0n-1);如果不指向任何节点,则为 null

    你的代码 接受原链表的头节点 head 作为传入参数。

    示例 1:

    img

    输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
    输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
    

    示例 2:

    img

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

    示例 3:

    img

    输入:head = [[3,null],[3,0],[3,null]]
    输出:[[3,null],[3,0],[3,null]]
    

    提示:

    • 0 <= n <= 1000
    • -104 <= Node.val <= 104
    • Node.randomnull 或指向链表中的节点。

2. 题目解析

- 题意分解

  1. 本题为对链表中的节点进行复制,节点包括下一节点链接和随机节点链接
  2. 本题的主要计算是2块,1是链表遍历,2是随机节点链接检索
  3. 基本的解法是双层循环,复制链表1层循环,随机节点检索1层循环,所以基本的时间算法复杂度为O(n^2)

- 优化思路

  1. 通常优化:减少循环层次

  2. 通常优化:增加分支,减少计算集

  3. 通常优化:采用内置算法来提升计算速度

  4. 分析题目特点,分析最优解

    1. 标准方法是双层循环,先复制,再检索

    2. 可以用哈希法【字典】优化查询

    3. 可以用递归法进行节点复制的解析,但是递归法有最大层次,超过就会报错


- 测量工具

  • 本地化测试说明:LeetCode网站测试运行时数据波动很大,因此需要本地化测试解决这个问题
  • CheckFuncPerf(本地化函数用时和内存占用测试模块)已上传到CSDN,地址:Python算法题集_检测函数用时和内存占用的模块
  • 本题很难超时,本地化超时测试用例自己生成,详见【最优算法章节】

3. 代码展开

1) 标准求解【双层循环】

外层遍历,内层检索,网站性能良好,本地性能不堪

性能良好,超越83%在这里插入图片描述

import CheckFuncPerf as cfpclass Solution:@staticmethoddef copyRandomList_base(head):if not head: return Nonelist_origin, idx_origin = [], []while head:list_origin.append(head)idx_origin.append(-1)head = head.nextilen = len(list_origin)for iIdx in range(ilen):if list_origin[iIdx].random:idx_origin[iIdx] = list_origin.index(list_origin[iIdx].random)list_dist = []for iIdx in range(ilen):tmpNode = Node(list_origin[iIdx].val)list_dist.append(tmpNode)for iIdx in range(ilen-1):list_dist[iIdx].next = list_dist[iIdx+1]for iIdx in range(ilen):if idx_origin[iIdx] > -1:list_dist[iIdx].random = list_dist[idx_origin[iIdx]]return list_dist[0]result = cfp.getTimeMemoryStr(Solution.copyRandomList_base, ahead)
print(result['msg'], '执行结果 = {}'.format(result['result'].val))# 运行结果
函数 copyRandomList_base 的运行时间为 115717.23 ms;内存使用量为 17536.00 KB 执行结果 = 0

2) 改进版一【字典哈希】

双字典,将原链表、复制链表均存入字典,通过哈希优化检索

性能良好,超过81%在这里插入图片描述

import CheckFuncPerf as cfpclass Solution:@staticmethoddef copyRandomList_ext1(head):if not head: return Nonedict_origin = {} dict_new = {}  nodepre = Node(0) newnode = nodepreoriginhead = head idx = 0 while originhead:dict_origin[originhead] = idx newnode.next = Node(originhead.val)newnode = newnode.nextdict_new[idx] = newnode idx += 1 originhead = originhead.nextdict_new[idx] = None  newnode = nodepre.nextoriginhead = headwhile originhead:random_node = originhead.randomnodepos = dict_origin[random_node] if random_node else idxnode = dict_new[nodepos] newnode.random = nodenewnode = newnode.nextoriginhead = originhead.nextreturn nodepre.next  result = cfp.getTimeMemoryStr(Solution.copyRandomList_ext1, ahead)
print(result['msg'], '执行结果 = {}'.format(result['result'].val))# 运行结果
函数 copyRandomList_ext1 的运行时间为 390.09 ms;内存使用量为 19492.00 KB 执行结果 = 0

3) 改进版二【单层哈希】

将原链表、复制链表存入一个字典,通过哈希优化定位

马马虎虎,超过69%在这里插入图片描述

import CheckFuncPerf as cfpclass Solution:@staticmethoddef copyRandomList_ext2(head):if not head: return Nonecurnode = headdict_nodes = {}  while curnode:dict_nodes[curnode] = Node(curnode.val)curnode = curnode.next  curnode = headwhile curnode:dict_nodes[curnode].next = dict_nodes[curnode.next] if curnode.next else Nonedict_nodes[curnode].random = dict_nodes[curnode.random] if curnode.random else Nonecurnode = curnode.nextreturn dict_nodes[head]result = cfp.getTimeMemoryStr(Solution.copyRandomList_ext2, ahead)
print(result['msg'], '执行结果 = {}'.format(result['result'].val))# 运行结果
函数 copyRandomList_ext2 的运行时间为 170.04 ms;内存使用量为 12820.00 KB 执行结果 = 0

4) 改进版三【递归大法】

采用递归方式进行节点复制,本地性能都不好,不管是否报错

性能优良,超越85%在这里插入图片描述

import CheckFuncPerf as cfpclass Solution:@staticmethoddef copyRandomList_ext3(head):def copyNode(head, dict_nodes):if not head: return Nonewhile head not in dict_nodes.keys():headNew = Node(head.val)  # 拷贝新节点dict_nodes[head] = headNew  # 记录到哈希表中headNew.next = copyNode(head.next, dict_nodes)headNew.random = copyNode(head.random, dict_nodes)return dict_nodes[head]dict_nodes = {}return copyNode(head, dict_nodes)result = cfp.getTimeMemoryStr(Solution.copyRandomList_ext3, ahead)
print(result['msg'], '执行结果 = {}'.format(result['result'].val))# 运行结果
Traceback (most recent call last):......
[Previous line repeated 991 more times]
RecursionError: maximum recursion depth exceeded

4. 最优算法

根据本地日志分析,最优算法为第3种copyRandomList_ext2

ilen = 100000
list_node =[]
for iIdx in range(ilen):tmpListnode = Node(iIdx)list_node.append(tmpListnode)
for iIdx in range(ilen-1):list_node[iIdx].next = list_node[iIdx+1]
for iIdx in range(ilen):list_node[iIdx].random = list_node[random.randint(1, ilen)-1]
ahead = list_node[0]
result = cfp.getTimeMemoryStr(Solution.copyRandomList_base, ahead)
print(result['msg'], '执行结果 = {}'.format(result['result'].val))# 算法本地速度实测比较
# 链表长度900
函数 copyRandomList_base 的运行时间为 10.00 ms;内存使用量为 296.00 KB 执行结果 = 0
函数 copyRandomList_ext1 的运行时间为 1.00 ms;内存使用量为 196.00 KB 执行结果 = 0
函数 copyRandomList_ext2 的运行时间为 1.00 ms;内存使用量为 128.00 KB 执行结果 = 0
函数 copyRandomList_ext3 的运行时间为 2.00 ms;内存使用量为 1104.00 KB 执行结果 = 0
# 链表长度10W
函数 copyRandomList_base 的运行时间为 115717.23 ms;内存使用量为 17536.00 KB 执行结果 = 0
函数 copyRandomList_ext1 的运行时间为 390.09 ms;内存使用量为 19492.00 KB 执行结果 = 0
函数 copyRandomList_ext2 的运行时间为 170.04 ms;内存使用量为 12820.00 KB 执行结果 = 0
Traceback (most recent call last):    # 递归法 copyRandomList_ext3 超时......[Previous line repeated 991 more times]
RecursionError: maximum recursion depth exceeded

一日练,一日功,一日不练十日空

may the odds be ever in your favor ~

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

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

相关文章

Netty基本组件

编解码器 编码器 类作用MessageToByteEncoder将消息编码为字节MessageToMessageEncoder将一种消息编码为另一种消息 解码器 类作用ByteToMessageDecoder将字节解码为消息MessageToMessageDecoder将一种消息解码为另一种消息

4 月 9 日至 4 月 10 日,Hack.Summit() 2024 首聚香江

Hack.Summit() 是一系列 Web3 开发者大会。2024 年的活动将于 2024 年 4 月 9 日至 4 月 10 日在香港数码港举行。自十年前首次举办以来&#xff0c;此次会议标志着 Hack.Summit() 首次在亚洲举办&#xff0c;香港被选为首次亚洲主办城市&#xff0c;这对 Hack VC 和该地区都具…

CMU和ETH联合研发了一个名为 「敏捷但安全」的新框架,为四足机器人在复杂环境中实现高速运动提供了解决方案

在高速机器人运动领域&#xff0c;实现同时兼顾速度和安全一直是一大挑战。但现在&#xff0c;卡内基梅隆大学&#xff08;CMU&#xff09;和苏黎世联邦理工学院&#xff08;ETH&#xff09;的研究团队带来了突破性进展。他们开发的新型四足机器人算法&#xff0c;不仅能在复杂…

集团企业大数据应用:突破痛点,释放数据价值

在数字经济日益崛起的背景下&#xff0c;集团企业以其管理范围广泛、业务领域多元化和分支机构复杂化的特性&#xff0c;在市场竞争中扮演着重要角色。为了维持和提升这种竞争力&#xff0c;大数据应用成为了集团企业不可或缺的战略工具。然而&#xff0c;在实际应用中&#xf…

使用MinIO S3存储桶备份Weaviate

Weaviate 是一个开创性的开源向量数据库&#xff0c;旨在通过利用机器学习模型来增强语义搜索。与依赖关键字匹配的传统搜索引擎不同&#xff0c;Weaviate 采用语义相似性原则。这种创新方法将各种形式的数据&#xff08;文本、图像等&#xff09;转换为矢量表示形式&#xff0…

单片机学习笔记---直流电机驱动(PWM)

直流电机介绍 直流电机是一种将电能转换为机械能的装置。一般的直流电机有两个电极&#xff0c;当电极正接时&#xff0c;电机正转&#xff0c;当电极反接时&#xff0c;电机反转 直流电机主要由永磁体&#xff08;定子&#xff09;、线圈&#xff08;转子&#xff09;和换向器…

ModuleNotFoundError: No module named ‘torchvision.models.utils‘报错的一种解决方法

最近在做一个BEV项目&#xff0c;在配置环境的时候&#xff0c;遇到了报错的一个问题&#xff1a; ModuleNotFoundError: No module named ‘torchvision.models.utils’ 我开始以为是我没有安装torchvision pip install torchvision -i http://pypi.douban.com/simple输入这…

【机器学习笔记】12 聚类

无监督学习概述 监督学习 在一个典型的监督学习中&#xff0c;训练集有标签&#x1d466; &#xff0c;我们的目标是找到能够区分正样本和负样本的决策边界&#xff0c;需要据此拟合一个假设函数。无监督学习 与此不同的是&#xff0c;在无监督学习中&#xff0c;我们的数据没…

微服务学习Day4

文章目录 初始MQ同步通讯和异步通讯MQ常见技术介绍 RabbitMQ快速入门入门案例 SpringAMQP介绍例子WorkQueue模型exchange交换机消息转换器 初始MQ 同步通讯和异步通讯 MQ常见技术介绍 RabbitMQ快速入门 入门案例 SpringAMQP 介绍 例子 WorkQueue模型 exchange交换机 消息转换…

【JavaEE】_HTTP请求报头header

目录 1. Host 2. Content-Length与Content-Type 2.1 Content-Length 2.2 Content-Type 3. User-Agent&#xff08;UA&#xff09; 4. Referer 5. Cookie header的整体格式是“键值对”结构&#xff0c;一行是一个键值对&#xff0c;这些键值对都是HTTP定义好的、有特殊含…

输入捕获模式测频率PWM输入模式(PWMI)测占空比

一、概念介绍 输出比较&#xff1a; 比较电路输入的CNT、CCR大小关系 &#xff0c;在通道引脚输出高低电平 二、*频率知识、测量方法补充 * N/fc得到标准频率的时长&#xff0c;也就是待测频率的周期 测频法代码实现&#xff1a;修改对射式红外传感器计次&#xff08;上升沿…

怎样让MCU/SFU视频会议ovmedia 接入GB28281监控视频参会互动

在国内视频应用对GB监控接入是常规操作&#xff0c;很多系统需要接入监控视频交互处理。我们以ovmedia视频会议为例做一个接入互动。 GB28181协议在流媒体系统较为普及&#xff0c;我们以开源SRS系统对接监控端再接入会议&#xff08;也可以用商用GB流平台&#xff0c;操作基本…

Open CASCADE学习|分割

目录 1、添加头文件与源文件 GEOMAlgo_Splitter.h GEOMAlgo_Splitter.cpp 2、测试 2.1平面分割立方体 2.2以边分面 2.3以面分面 1、添加头文件与源文件 GEOMAlgo_Splitter.h // Copyright (C) 2007-2019 CEA/DEN, EDF R&D, OPEN CASCADE//// Copyright (C) 2003-2…

【大厂AI课学习笔记】【2.1 人工智能项目开发规划与目标】(4)数据准备的流程

今天学习的是数据准备的流程。 我们已经知道&#xff0c;数据准备占了AI项目超过一半甚至79%的时间。 那么数据准备&#xff0c;都做些什么&#xff0c;有哪些流程。 1.数据采集 观测数据人工收集调查问卷线上数据库 2.数据清洗 有缺失的数据有重复的数据有内容错误的数据…

51单片机编程应用(C语言):DS1302实时时钟

单片机计时的缺陷&#xff1a; 1.他的精度不高&#xff0c;没有时钟芯片精度高&#xff0c; 2.会占用单片机CPU的时间&#xff0c; 3.单片机的时钟无法掉电继续运行&#xff0c;&#xff08;最大的缺点&#xff09; DS1302芯片内部有备用电池&#xff0c;可以掉电继续计时…

fusion360 操作总结(不断更新)

平移缩放旋转快捷键 画布选择Windows 组合键macOS 组合键平移按住鼠标中键按住鼠标中键缩放滚动鼠标中键滚动鼠标中键动态观察旋转按住 Shift 键并按住鼠标中键按住 Shift 键并按住鼠标中键绕点动态观察按住 Shift 键单击并按住鼠标中键按住 Shift 键单击并按住鼠标中键撤消Ct…

MCU看门狗

目录 一、独立看门狗(IWDG) 1、IWDG 主要作用 2、IWDG 主要特性 3、编程控制 4、注意地方 二、窗口看门狗(WWDG) 1、窗口看门狗作用&#xff1a; 2、窗口看门狗产生复位信号有两个条件&#xff1a; 3、WWDG 框图 4、WWDG 将要复位的时间 5、编程控制 一、独立看门…

STL:优先级队列的实现

STL中优先级队列本质上就是堆。在上一篇博客中讲到过&#xff1a;堆是一种完全二叉树&#xff0c;逻辑结构上看起来像树&#xff0c;但在物理结构中是存储在线性表中。与普通线性表不同的是&#xff0c;堆中数据大小是规律排列的&#xff1a;小堆中每个节点都大于它的父节点&am…

SpringBoot实战:打造企业资产管理系统

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

001kafka源码项目gradle报错UnsupportedClassVersionError-kafka-报错-大数据学习

1 报错提示 java.lang.UnsupportedClassVersionError: org/eclipse/jgit/lib/AnyObjectId has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0 如…