题目:
给你一个长度为 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
作为传入参数。
示例:
思路:
本题目文字较长,且内容较多,容易使做题者产生畏难情绪,感觉是在做阅读理解,无从下手。实际上,耐心读完后就会发现题目的要求很容易理解,就是要:创建出一个新链表,并且让这个新链表的所有节点的val、next、random都和原链表完全相同。理解到这里后,思路就比较清晰了,就是要用代码手动实现“复制”的操作。怎么复制、如何复制就是下一个问题。
题目要求创建一个新链表,把原链表的内容都复制到新链表上。首先我们要清楚复制哪些东西,是原链表每个节点的val、next、random。其中,val的复制难度不大,复杂的部分是它们之间的连接关系。因此,我们可以尝试采用哈希表(Python语言里可称为字典)来记录原节点和新复制节点之间的映射关系。这样,在遍历链表并复制节点时,我们可以方便地查找或存储新创建的节点。具体的实现步骤可以为:
1.遍历原链表:为每个节点创建一个新的复制节点,并将新节点插入到原节点之后。同时,将原节点与新节点的映射(复制)关系存储在哈希表中。
2.设置每个新节点的 next
和 random
指针:此时,我们可以利用哈希表来找到对应原节点的复制节点,从而连接指针,实现让 next
和 random
指针正确指向其新节点的效果。
3.将链表拆分为原链表和复制链表:由于每个新节点都紧跟在原节点之后,我们可以通过调整 next
指针来拆分链表,最后将“复制链表”连接到新链表头后,再返回新的头结点。
实现:
完整代码如下:(Python实现)
# Definition for a Node.
class Node:
def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
self.val = int(x)
self.next = next
self.random = random
def copyRandomList(head):
if not head:
return None
node_map = {} # 哈希表存储克隆关系
current = head
while current:
clone = Node(current.val) # 克隆节点
node_map[current] = clone # 存储克隆关系
clone.next = current.next # 把克隆节点放在原节点后
current.next = clone
current = current.next.next
current = head
while current:
if current.random:
current.next.random = node_map[current.random]
current = current.next.next
h = Node(0)
new_head = h
current = head
while current: # 尾插法创建链表
clone = current.next
current.next = clone.next
new_head.next = clone
new_head = new_head.next
current = current.next
return h.next
# 示例:构建链表: 1 -> 2 -> 3, random pointers: 1 -> 3, 2 -> 3, 3 -> 1
head = Node(1)
head.next = Node(2)
head.next.next = Node(3)
head.random = head.next.next
head.next.random = head.next.next
head.next.next.random = head
# 复制链表
cloned_head = copyRandomList(head)
# 输出克隆链表(供验证)
while cloned_head:
print(cloned_head.val, end='->')
cloned_head = cloned_head.next
题目来源:力扣(Leetcode)