题目 138. 复制带随机指针的链表 的描述如下,给定一个长度为
n
n
n 的链表,每个节点比普通的节点多了一个额外的随机指针 ramdom ,该指针可以指向链表中的任何节点或空节点。构造这个链表的深拷贝。所谓的深拷贝,就是完全生成一个新的对象,内存地址都是不同的,这样改变拷贝之前变量,就不会影响到拷贝的变量。
哈希映射 1
首先贴一个比较巧妙的解法,来自用户 skyliuhc,在官方题解下面的评论可以看到,他写的是 Java 的版本,这里我写成 Python 的版本:
主要的思路就是,先用一个循环把新旧链表对应的两个结点捆绑在一个二元组里,然后再用一个循环完成对新链表每个结点的 next 和 random 的赋值
class Solution:
def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
if not head: return None
cur = head
hashmap = {}
while cur:
hashmap[cur] = Node(cur.val)
cur = cur.next
cur = head
while cur:
hashmap[cur].next = hashmap[cur.next] if cur.next else None
hashmap[cur].random = hashmap[cur.random] if cur.random else None
cur = cur.next
return hashmap[head]
哈希映射 2
这个是我自己当时做题的时候想的方法,与前面一个的想法类似,也是打算用哈希表来记录新旧链表的结点,但是想法更为复杂了,具体的思路为:
- 1、先把最普通的链表构建起来,同时记录两个
Hashmap
- 1.1、
Node2Pos :旧链表的每个 Node 的位置 - 1.2、
Pos2Node :新链表每个位置对应的 Node - 2、同步遍历新旧两个链表,得到当前位置的旧节点的 random node 对应的位置
pos ; - 3、通过位置
pos 得到新链表的 Node,就知道当前结点的 random 要指向哪里;
class Solution:
def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
if not head: return None
Node2Pos = {}
Pos2Node = {}
newPreHead = Node(0)
new_ptr = newPreHead
old_ptr = head
idx = 0
while old_ptr:
Node2Pos[old_ptr] = idx
new_ptr.next = Node(old_ptr.val)
new_ptr = new_ptr.next
Pos2Node[idx] = new_ptr
idx += 1
old_ptr = old_ptr.next
Pos2Node[idx] = None
new_ptr = newPreHead.next
old_ptr = head
while old_ptr:
random_node = old_ptr.random
pos = Node2Pos[random_node] if random_node else idx
node = Pos2Node[pos]
new_ptr.random = node
new_ptr = new_ptr.next
old_ptr = old_ptr.next
return newPreHead.next
回溯 + 哈希表
官方题解:利用回溯法,让每个节点的拷贝操作相互独立,对于当前结点,首先进行拷贝,然后进行「当前节点的后继节点」和「当前节点的随机指针指向的节点」拷贝,拷贝完成后将创建的新节点的指针返回,即可完成当前节点的两指针的赋值。
具体的做法是:
- 先创建一个哈希表
cachedNode ,从头结点开始遍历; - 如果结点为空,返回
None ; - 创建一个新的结点,其值与当前遍历的结点值
val 一样; - 然后遍历地去对
next 和 random 赋值;
class Solution:
def __init__(self,):
self.cachedNode = {}
def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
if not head: return None
if head not in self.cachedNode.keys():
headNew = Node(head.val)
self.cachedNode[head] = headNew
headNew.next = self.copyRandomList(head.next)
headNew.random = self.copyRandomList(head.random)
return self.cachedNode[head]
迭代 + 节点拆分
- 对于链表
A => B => C ,可以将其变成 A => A' => B => B' => C => C' ,其中 A' 为 A 的拷贝结点
class Solution:
def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
if not head: return None
node = head
while node:
nodeNew = Node(node.val)
nodeNew.next = node.next
node.next = nodeNew
node = node.next.next
node = head
while node:
nodeNew = node.next
nodeNew.random = node.random.next if node.random else None
node = node.next.next
headNew = head.next
node = head
while node:
nodeNew = node.next
node.next = node.next.next
nodeNew.next = nodeNew.next.next if nodeNew.next else None
node = node.next
return headNew
|