Copy List with Random Pointer
Each node of a singly linked list has the usual next pointer plus a second random pointer that points to any node in the list or to null. Build a deep copy: a brand-new list of new nodes whose next and random pointers mirror the original's structure exactly, but point only among the new nodes — no new node may reference any original node. Return the head of the copied list. The original list must be left unmodified.
- The number of nodes is in the range [0, 1000]
- -10⁴ <= Node.val <= 10⁴
- random points to a node in the list, or is null
head = [[7,null],[13,0],[11,4],[10,2],[1,0]][[7,null],[13,0],[11,4],[10,2],[1,0]]head = [[1,1],[2,1]][[1,1],[2,1]]head = [][]Cloning a linked list where nodes have "random" pointers is a dependency puzzle. In a standard list, you only need to know the next node to build the copy. But with random pointers, a node might point to someone much further down the line who hasn't been created yet. You can't set a random pointer to a clone until that clone actually exists in memory.
A common way to solve this is using a Hash Map to store the mapping between every original node and its new copy. This allows you to look up any "clone" in O(1) time, but it costs O(N) extra space.
# Hash Map Approach (O(N) Space)
mapping = {None: None}
curr = head
# 1. Create all clones and store in map
while curr:
mapping[curr] = Node(curr.val)
curr = curr.next
# 2. Connect next and random links
curr = head
while curr:
mapping[curr].next = mapping[curr.next]
mapping[curr].random = mapping[curr.random]
curr = curr.next
return mapping[head]To achieve O(1) space, we can use the original list itself as the "address book" by performing a technique called DNA Interleaving.
The strategy works in three distinct phases:
- Interweave: For every node X, we create its clone X' and insert it immediately after X. This creates a temporary "DNA chain" like X -> X' -> Y -> Y'.
- Mirror Randoms: Because every clone X' is sitting right next to its parent X, we can find the correct random target easily: X'.random must be X.random.next.
- Extract: We carefully snip the links to separate the original list from the clone list, restoring the original next pointers while stitching the clones together into a fresh deep copy.
# 1. Interweave (DNA splicing)
curr = head
while curr:
new_node = Node(curr.val, curr.next)
curr.next = new_node
curr = new_node.next
# 2. Mirror Random Pointers
curr = head
while curr:
if curr.random:
curr.next.random = curr.random.next
curr = curr.next.next
# 3. Extract Clone and Restore Original
dummy = Node(0)
copy_tail = dummy
curr = head
while curr:
# Stitch the copy together
copy_tail.next = curr.next
copy_tail = copy_tail.next
# Restore the original next link
curr.next = curr.next.next
curr = curr.next
return dummy.nextPhase 1: Interweaving (DNA Splicing)
Phase 2: Mirroring Random Pointers
Phase 3: Extracting Clone and Restoring Original
3-Pass In-Place Algorithm
Phase Details
Phase 1: Interleaving
Create copy nodes and interleave them with the original: A -> A' -> B -> B' -> C -> C'. Note: Original random pointers exist but are not yet copied.
Interleaving copy nodes inside the original list eliminates the need for a Hash Map (O(N) space). We trade O(1) space for O(N) time.
Time Complexity: O(N) | Space Complexity: O(1) extra space. The most elegant solution for cloning with random pointers.