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.rhkb.cn/news/255771.html

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

相关文章

【深度学习】pytorch 与 PyG 安装(pip安装)

【深度学习】pytorch 与 PyG 安装&#xff08;pip安装&#xff09; 一、PyTorch安装和配置&#xff08;一&#xff09;、安装 CUDA&#xff08;二&#xff09;、安装torch、torchvision、torchaudio三个组件&#xff08;1&#xff09;下载镜像文件&#xff08;2&#xff09;创建…

C++入门(上)

文章目录 1:什么是C2.C的发展史3:C关键字(C98)4:命名空间4.1:命名空间的概念4.2:命名空间的定义4.3:命名空间的使用4.3.1加命名空间的名称以及域作用限定符4.3.2:使用using将命名空间中某个成员引入4.3.3:使用using namespace 命名空间名称展开命名空间代码1代码2 5:C输入与输出…

第72讲后台管理Container布局实现

新建layout目录 登录成功后&#xff0c;跳转layout布局容器页面 login页面&#xff1a; 导入router import router from "/router";登录成功&#xff0c;跳转后台管理页面 选用布局容器&#xff1a; <template><div class"common-layout">…

【Java EE】----Spring框架创建和使用

1.Spring框架创建 创建一个maven项目 添加Spring框架支持 <dependencies> 上下文<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.3.RELEASE</version></depende…

基于Seaborn和Matplotlib的可视化案例分析

处理数据有时会有点无聊。将原始数据转换为可理解的格式是整个过程中最重要的部分之一&#xff0c;那么为什么只停留在数字上&#xff0c;当我们可以将数据可视化为令人兴奋的图表时&#xff0c;这些图表可以在python中获取。这篇文章将重点探索耐人寻味的预处理之旅。 Seabor…

Python进阶----在线翻译器(Python3的百度翻译爬虫)

目录 一、此处需要安装第三方库requests: 二、抓包分析及编写Python代码 1、打开百度翻译的官网进行抓包分析。 2、编写请求模块 3、输出我们想要的消息 三、所有代码如下&#xff1a; 一、此处需要安装第三方库requests: 在Pycharm平台终端或者命令提示符窗口中输入以下代…

npm修改镜像源

背景&#xff1a;切换npm镜像源是经常遇到的事&#xff0c;下面记录下具体操作命令 1. 打开终端运行"npm config get registry"命令来查看当前配置的镜像源 npm config get registry2. 修改成淘宝镜像源"https://registry.npmjs.org/" npm config set re…

腾讯云4核8G12M轻量应用服务器性能够用吗?支持多少人?

腾讯云轻量4核8G12M轻量应用服务器支持多少人同时在线&#xff1f;通用型-4核8G-180G-2000G&#xff0c;2000GB月流量&#xff0c;系统盘为180GB SSD盘&#xff0c;12M公网带宽&#xff0c;下载速度峰值为1536KB/s&#xff0c;即1.5M/秒&#xff0c;假设网站内页平均大小为60KB…

C++重新入门-C++变量作用域

目录 1.C变量定义 2.C作用域 3.局部变量 4.全局变量 5.块作用域变量 6.初始化局部变量和全局变量 1.C变量定义 一般来说有三个地方可以定义变量&#xff1a; 在函数或一个代码块内部声明的变量&#xff0c;称为局部变量。 在函数参数的定义中声明的变量&#xff0c;称为…

nodejs爬虫框架

nodejs爬虫框架 在Node.js中&#xff0c;有一些常用的爬虫框架可以帮助你实现网页抓取和数据提取的任务。以下是几个流行的Node.js爬虫框架&#xff1a; 1. **Puppeteer**: Puppeteer 是由 Google 开发的一个用于控制 headless Chrome 或 Chromium 浏览器的 Node.js 库。它提供…

浅谈人工智能之深度学习~

目录 前言&#xff1a;深度学习的进展 一&#xff1a;深度学习的基本原理和算法 二&#xff1a;深度学习的应用实例 三&#xff1a;深度学习的挑战和未来发展方向 四&#xff1a;深度学习与机器学习的关系 五&#xff1a;深度学习与人类的智能交互 悟已往之不谏&#xff0…

LeetCode周赛384 题解

AK 第 384 场周赛 - 力扣&#xff08;LeetCode&#xff09; 前两题都是签到, 略。 第三题: 回文字符串的最大数量 1、题意: 给定一个字符串数组&#xff0c;总字符数量不超过1e6, 可以交换其中的任意两个字符&#xff0c;问能构造最多几个回文字符串。 2、题解: 首先我…

uniapp /微信小程序 使用map组件实现手绘地图方案

获取地图范围 点图拾取坐标-地图开放平台|腾讯位置服务 获取需要手绘地图左下角和右上角GPS坐标 以北京故宫为例&#xff1a; 截取需要手绘地图进行手绘地图制作 ​​​​​​​​​​​​​​ 素材处理 由于地图素材文件比较大&#xff0c;小程序又限制包大小<2M,无…

Spring Native 解放 JVM

一、Spring Native 是什么 Spring Native可以通过GraalVM将Spring应用程序编译成原生镜像&#xff0c;提供了一种新的方式来部署Spring应用。与Java虚拟机相比&#xff0c;原生镜像可以在许多场景下降低工作负载&#xff0c;包括微服务&#xff0c;函数式服务&#xff0c;非常…

(已解决)将overleaf上的文章paper上传到arxiv上遇到的问题。

文章目录 前言初级问题后续问题 前言 首先说一点&#xff0c;将paper的pdf文件直接上传arxiv是不行的&#xff0c;arxiv要求我们要上传源文件&#xff0c;所以才这么麻烦。 初级问题 首先上传文件之后有可能会在下面这个界面出现问题&#xff0c;这里一般都比较常见的问题&a…

重温阿里云宝塔面板部署前后端项目

首先祝大家新年快乐啊&#xff01; 回到老家&#xff0c;便打算趁这一段空闲时间提升一下自己&#xff0c;重点是学习实践一下echarts相关内容&#xff0c;很多公司项目都需要实现可视化&#xff0c;所以在bilibili上找了黑马的一个教程开始学习&#xff0c;不同的是&#xff…

【JAVA WEB】 百度热榜实现 新闻页面 Chrome 调试工具

目录 百度热榜 新闻页面 Chrome 调试工具 --查看css属性 打开调试工具的方式 标签页含义 百度热榜 实现效果&#xff1a; 实现代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"vi…

《CSS 简易速速上手小册》第4章:视觉美学(2024 最新版)

文章目录 4.1 颜色理论在 CSS 设计中的应用&#xff1a;网页的调色盘4.1.1 基础知识4.1.2 重点案例&#xff1a;创建一个具有情感设计的登录页面4.1.3 拓展案例 1&#xff1a;使用颜色增强信息的可视化表示4.1.4 拓展案例 2&#xff1a;利用颜色创建网站的品牌身份 4.2 字体与文…

生成式人工智能攻击的一年:2024

趋势科技最近公布了其关于预期最危险威胁的年度研究数据。生成人工智能的广泛可用性和质量将是网络钓鱼攻击和策略发生巨大变化的主要原因。 趋势科技宣布推出“关键可扩展性”&#xff0c;这是著名年度研究的新版本&#xff0c;该研究分析了安全形势并提出了全年将肆虐的网络…

JavaEE作业-实验二

目录 1 实验内容 2 实验要求 3 思路 4 核心代码 5 实验结果 1 实验内容 实现两个整数求和的WEB程序 2 实验要求 ①采用SpringMVC框架实现 ②数据传送到WEB界面采用JSON方式 3 思路 ①创建一个SpringMVC项目&#xff0c;配置好相关的依赖和配置文件。 ②创建一个Con…