复制带随机指针的链表
题目
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的 深拷贝。
我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
这个题目, 主要时考察链表的应用, 同时这个题目还是很有创新性的, 加入了随机指针, 而且用深拷贝链表。
这个题目拿出来将的主要目的就是想扩展下思路,
下面这三种方法都是很好的, 尤其是第一种, 第二种算法也是很好的, 第三种也不错。
方法一:O(1)空间复杂度
这个思路很简单, 但是还是要注意一些细节
-
首先遍历给定的链表, 在原始链表每个节点i的旁边拷贝一个新的节点j, 然后i的后一个节点指向j,然后j的next指向原来i的next节点。
-
然后遍历新生成的这个链表, 将新节点的random指针指向对应的位置, 即也就是将上图中节点A’, B’ , C’的random指向A, B , C的random的next
- 最后就是解除节点N到N‘之间的连接, 建立起正确的next关系。
"""
# 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
"""
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
# print(head.next.next.val)
if head is None:
return head
point = head
while point:
node = Node(point.val, point.next, None)
point.next = node
point = node.next
# print("****")
res = head.next
point_1= head
while point_1:
if point_1.random != None:
point_1.next.random = point_1.random.next
else: point_1.next.random = None
point_1 = point_1.next.next
point_old, point_new = head, head.next
while point_old:
point_old.next = point_old.next.next if point_old.next else None
point_new.next = point_new.next.next if point_new.next else None
point_old, point_new = point_old.next, point_new.next
return res
方法二:回溯
主要是将next和random指针平等对待, 用递归的算法实现, (DFS)
可以去参考我前一篇博客【DFS和BFS】
class Solution(object):
"""
:type head: Node
:rtype: Node
"""
def __init__(self):
# Dictionary which holds old nodes as keys and new nodes as its values.
self.visitedHash = {}
def copyRandomList(self, head):
if head == None:
return None
# If we have already processed the current node, then we simply return the cloned version of it.
if head in self.visitedHash:
return self.visitedHash[head]
# create a new node
# with the value same as old node.
node = Node(head.val, None, None)
# Save this value in the hash map. This is needed since there might be
# loops during traversal due to randomness of random pointers and this would help us avoid them.
self.visitedHash[head] = node
# Recursively copy the remaining linked list starting once from the next pointer and then from the random pointer.
# Thus we have two independent recursive calls.
# Finally we update the next and random pointers for the new node created.
node.next = self.copyRandomList(head.next)
node.random = self.copyRandomList(head.random)
return node
方法三:O(N)空间复杂度
这个思路也挺清晰的:
- 首先是遍历这个链表
- 我们首先用一个字典D去存储我们已经访问过的节点信息,对遍历中的每个节点, 我们先去查询D中有没有其信息, 如果有的话, 我们就不用创建节点, 然后配置其节点的random 和 next指针, 没有的话, 我们就创建一个节点, 然后将节点信息加入D中, 表示我们已经访问过该节点。
- 对于random指针和next指针, 我们要求查询它们指向的节点有没有在字典D中, 如果有的, 直接取值, 没有的话就创建节点,然后将节点信息加入D中, 表示我们已经访问过该节点。
"""
# 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
"""
class Solution:
def __init__(self):
self.visited = {}
def getCloneNode(self, node):
if node:
if node in self.visited:
return self.visited[node]
else:
self.visited[node] = Node(node.val, None, None)
return self.visited[node]
return None
def copyRandomList(self, head: 'Node') -> 'Node':
if not head:
return head
old_node = head
new_node = Node(old_node.val, None, None)
self.visited[old_node] = new_node
while old_node != None:
new_node.random = self.getCloneNode(old_node.random)
new_node.next = self.getCloneNode(old_node.next)
old_node =old_node.next
new_node = new_node.next
return self.visited[head]
参考文献:
【1】Leecode-138-138. 复制带随机指针的链表-官方题解
【2】【DFS和BFS】