随机链表的复制
随机链表的复制
题意
给你一个长度为 n
的链表,每个节点包含一个额外增加的随机指针 random
,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n
个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next
指针和 random
指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X
和 Y
两个节点,其中 X.random --> Y
。那么在复制链表中对应的两个节点 x
和 y
,同样有 x.random --> y
。
返回复制链表的头节点。
用一个由 n
个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index]
表示:
val
:一个表示 Node.val
的整数。random_index
:随机指针指向的节点索引(范围从 0
到 n-1
);如果不指向任何节点,则为 null
。
你的代码 只 接受原链表的头节点 head
作为传入参数。
思路一:哈希表
对于数据结构复制,记住最简单的方式:一个哈希表 + 两次遍历。
第一次遍历专门克隆节点,借助哈希表把原始节点和克隆节点的映射存储起来;第二次专门组装节点,照着原数据结构的样子,把克隆节点的指针组装起来。
题目如果让你克隆带随机指针的二叉树,或者克隆图,都是一样的,只不过是遍历的方式从 for 循环迭代遍历变成 traverse 递归函数遍历罢了。
若头节点
head
为空节点,直接返回null
。初始化: 哈希表
map
, 节点cur
指向头节点。复制链表:
- 建立新节点,并向
map
添加键值对(原 cur 节点, 新 cur 节点)
。 cur
遍历至原链表下一节点。
- 建立新节点,并向
构建新链表的引用指向:
- 构建新节点的
next
和random
引用指向。 cur
遍历至原链表下一节点。
- 构建新节点的
返回值: 新链表的头节点 map[cur] 。
代码:
class Solution {
public Node copyRandomList(Node head) {
if (head == null) return null;
Node cur = head;
Map<Node, Node> map = new HashMap<>();
// 第一次复制,并建立 “原节点 -> 新节点” 的 Map 映射
while(cur != null) {
map.put(cur, new Node(cur.val));
cur = cur.next;
}
cur = head;
// 第二次复制,构建新链表的 next 和 random 指向
while(cur != null) {
map.get(cur).next = map.get(cur.next);
map.get(cur).random = map.get(cur.random);
cur = cur.next;
}
// 返回新链表的头节点
return map.get(head);
}
}
思路二:拼接 + 拆分
相比于使用哈希表,这种做法可以降低空间复杂度
考虑构建 原节点 1 -> 新节点 1 -> 原节点 2 -> 新节点 2 -> ……
的拼接链表,如此便可在访问原节点的 random
指向节点的同时找到新对应新节点的 random
指向节点。
构建拼接链表
复制
random
指针:当访问原节点p
的随机指向节点p.random
时,对应新节点q.next
的随机指向节点为p.random.next
。拆分两个链表:设置
p
/cur
分别指向原 / 新链表头节点,遍历执行 p.next = p.next.next
和cur.next = cur.next.next
将两链表拆分开。返回新链表的头节点
dummy.next
即可。
class Solution {
public Node copyRandomList(Node head) {
// 复制每个节点,并将原链表和复制链表连在一起。
for(Node p = head; p != null; p = p.next.next)
{
Node q = new Node(p.val);
q.next = p.next;
p.next = q;
}
// 复制random指针
for(Node p = head; p != null; p = p.next.next)
{
if(p.random != null)
p.next.random = p.random.next;
}
//拆分两个链表,并复原原链表
Node dummy = new Node(-1), cur = dummy;
for(Node p = head; p != null; p = p.next)
{
Node q = p.next;
cur = cur.next = q;
p.next = q.next;
}
return dummy.next;
}
}