LeetCode 138: Copy List with Random Pointer - 深度讲解与讨论总结
🧠 题目描述
给定一个特殊链表,每个节点除了 val
和 next
外,还有一个 random
指针,指向链表中的任意一个节点或为 None
。
目标:深拷贝这个链表,返回一个结构完全相同的新链表(值相同,但节点是新对象)。
✅ 方法一:哈希表 + 两次遍历(空间 O(n),逻辑简单)
class Solution:
def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
if not head:
return None
old_to_new = {}
curr = head
while curr:
old_to_new[curr] = Node(curr.val)
curr = curr.next
curr = head
while curr:
old_to_new[curr].next = old_to_new.get(curr.next)
old_to_new[curr].random = old_to_new.get(curr.random)
curr = curr.next
return old_to_new[head]
✅ 方法二:原地插入 + 拆分链表(空间 O(1),推荐)
🌱 思路步骤:
- 在每个节点后插入一个新节点(A → A’ → B → B’)
- 设置新节点的
random
指针(A'.random = A.random.next
) - 拆分出两个独立链表(旧链表恢复、新链表独立)
class Solution:
def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
if not head:
return None
# Step 1: 插入新节点
cur = head
while cur:
newNode = Node(cur.val)
newNode.next = cur.next
cur.next = newNode
cur = newNode.next
# Step 2: 设置 random 指针
cur = head
while cur:
if cur.random:
cur.next.random = cur.random.next
cur = cur.next.next
# Step 3: 拆分链表
old = head
new = head.next
newhead = head.next
while old:
old.next = old.next.next
if new.next:
new.next = new.next.next
old = old.next
new = new.next
return newhead
🔍 深入解释关键语句
cur.next.random = cur.random.next
cur
: 当前原节点(如 A)cur.next
: 对应的新节点 A’cur.random
: 原链表中的 random 目标(如 C)cur.random.next
: C 的复制节点 C’
所以:A'.random = C'
🧠 链表指针变量理解
cur
和head
初始时指向同一个对象(引用)- 当
cur
向后走,head
不变,可以用head
重新遍历整个链表 - 这是链表操作中的典型特性:操作指针移动,头节点保留入口
✅ 指针总结:old、new、new_head 的区别与作用
指针名 | 作用 | 是否会移动 | 最终位置 |
---|---|---|---|
old | 遍历原链表 | ✅ 会 | None |
new | 遍历新链表 | ✅ 会 | None |
new_head | 记录新链表的头 | ❌ 不会 | A’(头) |
🎯 总结一句话:
利用在原链表中插入复制节点的技巧,节省了额外空间,
通过 “cur.next” 和 “cur.random.next” 达成了精巧的结构复制,
最后再将链表一分为二,新旧链表独立,各不干扰。
以上是我们围绕这道题的全部分析和代码讲解 🙌
你现在对链表的结构操作和引用传递理解已经非常深入了!