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

news2025/1/21 0:00:40

 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 cfp

class Solution:
 @staticmethod
 def copyRandomList_base(head):
     if not head: return None
     list_origin, idx_origin = [], []
     while head:
         list_origin.append(head)
         idx_origin.append(-1)
         head = head.next
     ilen = 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 cfp

class Solution:
 @staticmethod
 def copyRandomList_ext1(head):
     if not head: return None
     dict_origin = {} 
     dict_new = {}  
     nodepre = Node(0) 
     newnode = nodepre
     originhead = head 
     idx = 0 
     while originhead:
         dict_origin[originhead] = idx 
         newnode.next = Node(originhead.val)
         newnode = newnode.next
         dict_new[idx] = newnode 
         idx += 1 
         originhead = originhead.next
     dict_new[idx] = None  
     newnode = nodepre.next
     originhead = head
     while originhead:
         random_node = originhead.random
         nodepos = dict_origin[random_node] if random_node else idx
         node = dict_new[nodepos] 
         newnode.random = node
         newnode = newnode.next
         originhead = originhead.next
     return 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 cfp

class Solution:
 @staticmethod
 def copyRandomList_ext2(head):
     if not head: return None
     curnode = head
     dict_nodes = {}  
     while curnode:
         dict_nodes[curnode] = Node(curnode.val)
         curnode = curnode.next  
     curnode = head
     while curnode:
         dict_nodes[curnode].next = dict_nodes[curnode.next] if curnode.next else None
         dict_nodes[curnode].random = dict_nodes[curnode.random] if curnode.random else None
         curnode = curnode.next
     return 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 cfp

class Solution:
 @staticmethod
 def copyRandomList_ext3(head):
     def copyNode(head, dict_nodes):
         if not head: return None
         while 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.coloradmin.cn/o/1455084.html

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

相关文章

Open CASCADE学习|TopoDS_Vertex与gp_Pnt相互转化

目录 gp_Pnt TopoDS_Vertex 关系和转换 使用场景 在Open CASCADE Technology (OCCT)中&#xff0c;TopoDS_Vertex和gp_Pnt是两种不同的数据类型&#xff0c;用于表示三维空间中的点。它们有不同的用途和特性&#xff1a; gp_Pnt gp_Pnt是OCCT几何库&#xff08;Geom&…

使用RegNet替换YOLOX中原始的Backbone

使用mmdetection 中的RegNet bcakbones替换YOLOX中原始的Backbone 将mmdet/models/backbones/regnet.py中相关的代码复制到YOLOX中&#xff0c;并进行适配 注意通道数要适配 in_channels [64, 160, 384] &#xff0c;可以通过调试后&#xff0c;先运行到后后端输出结果出&a…

算法练习-01背包问题【含递推公式推导】(思路+流程图+代码)

难度参考 难度&#xff1a;困难 分类&#xff1a;动态规划 难度与分类由我所参与的培训课程提供&#xff0c;但需 要注意的是&#xff0c;难度与分类仅供参考。且所在课程未提供测试平台&#xff0c;故实现代码主要为自行测试的那种&#xff0c;以下内容均为个人笔记&#xff0…

阿里云香港轻量应用服务器网络线路cn2?

阿里云香港轻量应用服务器是什么线路&#xff1f;不是cn2。 阿里云香港轻量服务器是cn2吗&#xff1f;香港轻量服务器不是cn2。阿腾云atengyun.com正好有一台阿里云轻量应用服务器&#xff0c;通过mtr traceroute测试了一下&#xff0c;最后一跳是202.97开头的ip&#xff0c;1…

RK3399平台开发系列讲解(USB篇)U盘等存储类设备

🚀返回专栏总目录 文章目录 一、什么是U盘等存储类设备二、U盘设备传输数据结构三、U盘识别需要打开的宏沉淀、分享、成长,让自己和他人都能有所收获!😄 📢介绍U盘等存储类设备。 一、什么是U盘等存储类设备 USB Mass Storage Device Class(USB MSC/UMS) USB大容量存…

如何在Linux系统中配置并优化硬盘的RAID

在Linux系统中配置和优化硬盘的RAID技术可以帮助提高数据存储性能和安全性。RAID&#xff08;Redundant Array of Independent Disks&#xff09;技术通过将多个硬盘组合起来&#xff0c;以增加性能、容量或冗余度&#xff0c;提高数据的可靠性和可用性。本文将介绍如何在Linux…

嵌入式学习-C++-Day6

思维导图 作业 以下是一个简单的比喻&#xff0c;将多态概念与生活中的实际情况相联系&#xff1a; 比喻&#xff1a;动物园的讲解员和动物表演 想象一下你去了一家动物园&#xff0c;看到了许多不同种类的动物&#xff0c;如狮子、大象、猴子等。现在&#xff0c;动物园里有一…

【机构vip教程】Unittest(1):unittest单元测试框架简介

unittest单元测试框架简介 unittest是python内置的单元测试框架&#xff0c;具备编写用例、组 织用例、执行用例、功能&#xff0c;可以结合selenium进行UI自动化测 试&#xff0c;也可以结合appium、requests等模块做其它自动化测试 官方文档&#xff1a;https://docs.pytho…

【计算机网络】P2P应用

将会在两个例子中得出结果 1&#xff0c;对等文件分发 &#xff1b;2&#xff0c;大型对等方社区中的服务器 P2P文件分发 自拓展性 直接成因是&#xff1a;对等方除了是比特的消费者外还是它们的重新分发者BitTorrent 一个用于文件分发的P2P协议洪流 torrent 参与一个特定文件…

day34打卡

day34打卡 860. 柠檬水找零 解法&#xff0c;贪心&#xff1a;局部最优&#xff1a;遇到账单20&#xff0c;优先消耗美元10&#xff0c;完成本次找零 -》全局最优&#xff1a;完成全部账单的找零。 遇到5&#xff0c;直接收下遇到10&#xff0c;找一个5元遇到20&#xff0c;…

CS50x 2024 - Lecture 6 - Python

00:00:00 - Introduction 00:01:01 - Python print("hello world")与c的显著差异 1.不必显式包含标准库 2.不再需要定义main函数 00:07:24 - Speller 00:13:41 - Filter from PIL import Image, ImageFilterbefore Image.open("bridge.jpg") after…

山西电力市场日前价格预测【2024-02-15】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2024-02-15&#xff09;山西电力市场全天平均日前电价为168.98元/MWh。其中&#xff0c;最高日前电价为366.42元/MWh&#xff0c;预计出现在18:30。最低日前电价为0.00元/MWh&#xff0c;预计出…

黑马程序员-瑞吉外卖day9

菜品分类下拉列表 CategoryController里面写 /*** 根据条件查询分类数据** param category* return*/GetMapping("/list")ApiOperation("菜品分类目录")public R<List<Category>> list(Category category) {List<Category> list cate…

洛夫克拉夫特“克苏鲁神话”艺术风格探索(一)

克苏鲁神话引入中国时间不长&#xff0c;研究的规模也不如国外大&#xff0c;但克苏鲁神话作为神话史、奇幻小说史上的重要节点&#xff0c;有很大的影响力与非常重要的研究意义。为了促进中文语境下克苏鲁神话元素的使用和创作、更好地设计克苏鲁的呼唤游戏模组&#xff08;剧…

0206-1-网络层

第 4 章 网络层 网络层提供的两种服务 虚电路服务 数据报服务 概要: 虚电路服务与数据报服务的对比 网际协议 IP 网际协议 IP 是 TCP/IP 体系中两个最主要的协议之一。与 IP 协议配套使用的还有四个协议&#xff1a; 地址解析协议 ARP (Address Resolution Protocol)逆地…

【论文精读】SimCLR2

摘要 本文提出了一个半监督学习框架&#xff0c;包括三个步骤&#xff1a;无监督或自监督的预训练&#xff1b;有监督微调&#xff1b;使用未标记数据进行蒸馏。具体改进有&#xff1a; 发现在半监督学习&#xff08;无监督预训练有监督微调&#xff09;中&#xff0c;对于较大…

嵌入式day24

开课复工啦~ 冲冲冲&#xff01; 文件IO&#xff1a; read函数和write函数&#xff1a; &#x1f4da; write 接口有三个参数&#xff1a; fd&#xff1a;文件描述符buf&#xff1a;要写入的缓冲区的起始地址&#xff08;如果是字符串&#xff0c;那么就是字符串的起始地址&…

语义分割-基础知识

1.cls_iou计算: cls0_iou预测正确的像素个数/&#xff08;预测为该类别的像素个数真实标签为该类别的像素个数-预测正确的像素个数&#xff09; mean_iou各个类别的像素预测准确值相加/像素总个数2.转置卷积(Transposed Convolution) 转置卷积不是卷积的逆运算 转置卷积也是卷…

黑猫带你学NandFlash第2篇:NandFlash部分相关名词释义

1 前言 1.1 声明 本文依据ONFI5.1、网络资料及个人工作经验整理而成&#xff0c;如有错误请留言。 文章为付费内容&#xff0c;已加入原创侵权保护&#xff0c;禁止私自转载及抄袭。 文章所在专栏&#xff1a;《黑猫带你学&#xff1a;NandFlash详解》 1.2 本文背景 本文关…

springboot198基于springboot的智能家居系统

基于Springboot的智能家居系统 **[摘要]**社会和科技的不断进步带来更便利的生活&#xff0c;计算机技术也越来越平民化。二十一世纪是数据时代&#xff0c;各种信息经过统计分析都可以得到想要的结果&#xff0c;所以也可以更好的为人们工作、生活服务。智能家居是家庭的重要…