LeetCode 138:复制带随机指针的链表 Copy List with Random Pointer
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的深拷贝。
A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.
Return a deep copy of the list.
示例:

输入:
{"$id":"1","next":{"$id":"2","next":null,"random":{"$ref":"2"},"val":2},"random":{"$ref":"2"},"val":1}
解释:
节点 1 的值是 1,它的下一个指针和随机指针都指向节点 2 。
节点 2 的值是 2,它的下一个指针指向 null,随机指针指向它自己。
提示:
- 你必须返回给定头的拷贝作为对克隆列表的引用。
Note:
- You must return the copy of the given head as a reference to the cloned list.
解题思路:
由于需要考虑随机指针,随机指针指向的节点可能是null,也可能是链表的最后一个节点,深拷贝下,你不能将新链表的随机指针指向原链表的节点,所以无法一遍得到新链表。
两种解题方法,一种是拷贝所有节点,暂存在一种数据结构内,然后再遍历一遍该数据结构,找到拷贝的节点,确定随机指针的指向。因为每个节点都要找到随机指针指向的节点,如果借助 散列表(字典) 其查找复杂度为 O(1) ,这样可以把总时间复杂度降到 O(n) ,由于要暂存所有节点,其空间复杂度为 O(n)。
另一种解题方法是需要三次遍历得到结果,简单来说就是先把每个节点拷贝,并把拷贝节点连接到原节点后面,依次类推。确定随机节点的关系之后再拆分链表。是一种很巧妙的思路:
原链表:1->2->3
复制每个节点到原节点后面:1->1->2->2->3->3
复制随机指针的指向关系
拆分链表:1->2->3, 1->2->3
复制随机指针指向时,原节点的随机节点下一个节点即为新节点的随机节点。假如原链表:1->2->3,节点1的随机节点为3,复制节点之后:1->1->2->2->3->3
我们只需将新节点(原节点1的后一个节点1)指向原节点的随机节点的后一个节点(原节点的随机节点为3,而复制之后随机节点3的后一个节点依然为3,但这个节点为新节点),最后拆分链表(链表拆分不影响节点指向关系)。其时间复杂度为 O(n),空间复杂度为 O(1)。
第一种方法:
Java:
class Solution {
public Node copyRandomList(Node head) {
if (head == null) return null;
HashMap<Node, Node> map = new HashMap<>();//借助hashMap
Node newHead = new Node(0);//虚拟头节点
Node cur = newHead;//指针指向当前节点
Node tmp;
while (head != null) {
if (map.containsKey(head)) {//查询原节点是否已存在于map
tmp = map.get(head);//如果存在直接取value值
} else {
tmp = new Node(head.val);//不存在则新建一个值相同的节点
map.put(head, tmp);//存入map,key为原节点,value为新节点
}
cur.next = tmp;
if (head.random != null) {//原节点的随机节点不为空的情况下
if (map.containsKey(head.random)) {//查询该随即节点是否已存在于map
tmp.random = map.get(head.random);//存在则直接将新节点的随机指针指向其value值
} else {
tmp.random = new Node(head.random.val);//不存在则新建一个值相同的随机节点
map.put(head.random, tmp.random);//存入map,key为原节点的随机节点,value为新节点的随机节点
}
}
head = head.next;//刷新原链表当前头节点
cur = tmp;//即cur=cur.next,刷新新链表当前节点
}
return newHead.next;
}
}
Python3:
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
if not head: return None
map = {}
newHead = Node(val=0, next=None, random=None)
cur = newHead
while head:
if head in map.keys():
tmp = map.get(head)
else:
tmp = Node(val=head.val, next=None, random=None)
map.setdefault(head, tmp)
cur.next = tmp
if head.random:
if head.random in map.keys():
tmp.random = map.get(head.random)
else:
tmp.random = Node(val=head.random.val, next=None, random=None)
map.setdefault(head.random, tmp.random)
head = head.next
cur = tmp
return newHead.next
第二种方法:
Java:
class Solution {
public Node copyRandomList(Node head) {
if (head == null) return null;
//复制节点 1->2->3 ==> 1->1->1->2->2->3->3
Node cur = head;
while (cur != null) {
Node next = cur.next;
Node tmp = new Node(cur.val);
cur.next = tmp;
tmp.next = next;
cur = next;
}
//复制随机指针
cur = head;
while (cur != null) {
//cur.next.random=>新节点的随机节点 cur.random.next=>原节点的随机节点的下一个节点
cur.next.random = cur.random == null ? null : cur.random.next;
cur = cur.next.next;//链表扩展一倍后肯定是偶数位链表,所以可以直接用cur.next.next
}
//分离节点
cur = head;
Node newHead = head.next;//新链表头节点
while (cur != null) {
Node tmp = cur.next;
cur.next = tmp.next;
cur = cur.next;
tmp.next = cur == null ? null : cur.next;
}
return newHead;
}
}
Python3:
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
if not head: return None
cur = head
while cur:
next = cur.next
tmp = Node(val=cur.val, next=next, random=None)
cur.next = tmp
cur = next
cur = head
while cur:
cur.next.random = cur.random.next if cur.random else None
cur = cur.next.next
cur = head
newHead = head.next
while cur:
tmp = cur.next
cur.next = tmp.next
cur = cur.next
tmp.next = cur.next if cur else None
return newHead
LeetCode 138:复制带随机指针的链表 Copy List with Random Pointer的更多相关文章
- [Java]LeetCode138. 复制带随机指针的链表 | Copy List with Random Pointer
A linked list is given such that each node contains an additional random pointer which could point t ...
- 复制带随机指针的链表 · Copy List with Random Pointer
[抄题]: 给出一个链表,每个节点包含一个额外增加的随机指针可以指向链表中的任何节点或空的节点. 返回一个深拷贝的链表. [思维问题]: [一句话思路]: 完完全全地复制,否则不好操作. 1-> ...
- Java实现 LeetCode 138 复制带随机指针的链表
138. 复制带随机指针的链表 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点. 要求返回这个链表的 深拷贝. 我们用一个由 n 个节点组成的链表来表示输入/ ...
- [LeetCode]138复制带随机指针的链表
题目描述: 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点. 要求返回这个链表的深度拷贝. 思路: 先遍历链表,将每个节点对应的随机指针指向的对象利用Hash ...
- LeetCode 138——复制带随机指针的链表
1. 题目 2. 解答 第一次遍历链表的时候,复制旧链表的节点值建立一个新的链表,同时定义一个 unordered_map 作为哈希表,哈希表的键为旧链表的节点指针,值为新链表的节点指针. 然后,第二 ...
- Leetcode 138. 复制带随机指针的链表
1.题目要求 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点. 要求返回这个链表的深度拷贝. 2.解题思路 (1)笔试思路(求速度,拿分数):使用哈希表 /* ...
- 【leetcode 138. 复制带随机指针的链表】解题报告
方法一:递归 unordered_map<Node*,Node*> dict; Node* copyRandomList(Node* head) { if (!head) return h ...
- LintCode-105.复制带随机指针的链表
复制带随机指针的链表 给出一个链表,每个节点包含一个额外增加的随机指针可以指向链表中的任何节点或空的节点. 返回一个深拷贝的链表. 挑战 可否使用O(1)的空间 标签 哈希表 链表 优步 code / ...
- 【LeetCode】138. Copy List with Random Pointer 复制带随机指针的链表 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人公众号:负雪明烛 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https:/ ...
随机推荐
- "犯罪心理"解读Mybatis拦截器
原文链接:"犯罪心理"解读Mybatis拦截器 Mybatis拦截器执行过程解析 文章写过之后,我觉得 "Mybatis 拦截器案件"背后一定还隐藏着某种设计动 ...
- 章节十四、7-如何切换到iFrame
以下案例使用https://jqueryui.com/网站为例. 一.如何确定元素是否包含在iFarme中? 1.按F12打开发者选项,定位到指定的元素. 2.向上查找元素是否被包含在ifarme标签 ...
- git实战经验(很实用)
推荐学习git很好的网站https://www.breakyizhan.com/git/216.html 以下内容,虽然编排不行,但是请认真的读下去,都是自己平时请自操作的,放心使用. 这是个人的gi ...
- 学习过程中遇到的python内置函数,后续遇到会继续补充进去
1.python内置函数isinstance(数字,数字类型),判断一个数字的数字类型(int,float,comple).是,返回True,否,返回False2.python内置函数id()可以查看 ...
- 【Go】使用压缩文件优化io (一)
原文连接:https://blog.thinkeridea.com/201906/go/compress_file_io_optimization1.html 最近遇到一个日志备份 io 过高的问题, ...
- Flume 简介及基本使用
一.Flume简介 Apache Flume是一个分布式,高可用的数据收集系统.它可以从不同的数据源收集数据,经过聚合后发送到存储系统中,通常用于日志数据的收集.Flume 分为 NG 和 OG (1 ...
- AbstractQueuedSynchronizer(AQS)源码解析
关于AQS的源码解析,本来是没有打算特意写一篇文章来介绍的.不过在写本学期课程作业中,有一门写了关于AQS的,而且也画了一些相关的图,所以直接拿过来分享一下,如有错误欢迎指正. ...
- 02_javaSE面试题:单例设计模式
还记得很多年前,面试就让在白板上写个单例模式,当时技术渣渣,还写的是class A.面试官还说,你就不能写个Singleton. 面试题 编程题:写一个Singleton示例 解析 什么是Single ...
- SQL Server温故系列(4):SQL 查询之集合运算 & 聚合函数
1.集合运算 1.1.并集运算 UNION 1.2.差集运算 EXCEPT 1.3.交集运算 INTERSECT 1.4.集合运算小结 2.聚合函数 2.1.求行数函数 COUNT 2.2.求和函数 ...
- Flink中的状态与容错
1.概述 Flink支持有状态计算,根据支持得不同状态类型,分别有Keyed State和Operator State.针对状态数据得持久化,Flink提供了Checkpoint机制处理:针对状态数据 ...