给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。

要求返回这个链表的深拷贝

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,随机指针指向它自己。

提示:

  1. 你必须返回给定头的拷贝作为对克隆列表的引用。

Note:

  1. 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的更多相关文章

  1. [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 ...

  2. 复制带随机指针的链表 · Copy List with Random Pointer

    [抄题]: 给出一个链表,每个节点包含一个额外增加的随机指针可以指向链表中的任何节点或空的节点. 返回一个深拷贝的链表. [思维问题]: [一句话思路]: 完完全全地复制,否则不好操作. 1-> ...

  3. Java实现 LeetCode 138 复制带随机指针的链表

    138. 复制带随机指针的链表 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点. 要求返回这个链表的 深拷贝. 我们用一个由 n 个节点组成的链表来表示输入/ ...

  4. [LeetCode]138复制带随机指针的链表

    题目描述: 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点. 要求返回这个链表的深度拷贝. 思路: 先遍历链表,将每个节点对应的随机指针指向的对象利用Hash ...

  5. LeetCode 138——复制带随机指针的链表

    1. 题目 2. 解答 第一次遍历链表的时候,复制旧链表的节点值建立一个新的链表,同时定义一个 unordered_map 作为哈希表,哈希表的键为旧链表的节点指针,值为新链表的节点指针. 然后,第二 ...

  6. Leetcode 138. 复制带随机指针的链表

    1.题目要求 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点. 要求返回这个链表的深度拷贝. 2.解题思路 (1)笔试思路(求速度,拿分数):使用哈希表 /* ...

  7. 【leetcode 138. 复制带随机指针的链表】解题报告

    方法一:递归 unordered_map<Node*,Node*> dict; Node* copyRandomList(Node* head) { if (!head) return h ...

  8. LintCode-105.复制带随机指针的链表

    复制带随机指针的链表 给出一个链表,每个节点包含一个额外增加的随机指针可以指向链表中的任何节点或空的节点. 返回一个深拷贝的链表. 挑战 可否使用O(1)的空间 标签 哈希表 链表 优步 code / ...

  9. 【LeetCode】138. Copy List with Random Pointer 复制带随机指针的链表 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人公众号:负雪明烛 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https:/ ...

随机推荐

  1. 用shell做简单的分布式计算

    # 分布式计算小试 # .首先获取本机host,作为实际计算时分区hash的种子 # .以*.*.*.44为主节点,*.*.*.///43为从节点 hash=`cat /root/data/host. ...

  2. select下拉箭头样式重置

    select{ appearance:none; -moz-appearance:none; -webkit-appearance:none; background: url("../ima ...

  3. Elasticsearch的使用

    我这边是以elasticsearch-2.4.3为例:引入maven <dependency> <groupId>org.elasticsearch.client</gr ...

  4. 一文看懂javaGC

    javaGC回收机制 在面试java后端开发的时候一般都会问到java的自动回收机制(GC).在了解java的GC回收机制之前,我们得先了解下Java虚拟机的内存区域. java虚拟机运行时数据区 j ...

  5. Arm架构下VUE环境的安装

    最近因为项目需要在arm环境下搭建vue环境,网上有基于Linux的 教程,路径略有不同,现整理如下 1.安装文件下载 1.下载地址:http://nodejs.cn/download/ 2.选择一个 ...

  6. 【记录】Field required a single bean, but 2 were found:

    重构遇到个小问题,记录下: 错误信息: *************************** APPLICATION FAILED TO START ************************ ...

  7. 【java自定义注解1】java自定义注解-属性

    关于自定义注解,以前项目种应用的不多,最近看新项目过程中发现了挺多自定义注解相关内容,使用起来比较巧妙,于是 总结了两种方式,记录如下: 第一种:结合反射进行属性注入,代码如下: 1.定义一个注解: ...

  8. 彻底弄懂UTF-8、Unicode、宽字符、locale

    目录 Unicode.UCS UTF8 宽字符类型wchar_t locale 为什么需要宽字符类型 多字节字符串和宽字符串相互转换 最近使用到了wchar_t类型,所以准备详细探究下,没想到水还挺深 ...

  9. 如何将 qsys 子模块设置为参数可调的方式给另外的qsys 调用

    Intel FPGA Quartus 软件中的 Qsys工具 也就是 Platform Designer 系统集成工具,可以 图形化界面操作 使用系统自带ip,自定义ip 系统自动生成 ip 间的连接 ...

  10. 精通并发与 Netty (二)常用的 rpc 框架

    Google Protobuf 使用方式分析 对于 RPC 协议来说,最重要的就是对象的发送与接收,这就要用到序列化与反序列化,也称为编码和解码,序列化与反序列化和网络传输一般都在对应的 RPC 框架 ...