Copy List with Random Pointer
Deep-copy a list where each node also has a random pointer to any node (or null).
Intuition
The hard part is wiring random in the copy — the target may not exist yet when you meet the pointer. Interleave copies with originals (A→A'→B→B'…): then every original's random copy is exactly random.next, no map needed.
The obvious solution is a hash map from original node to clone; the O(1)-space trick is to store that mapping inside the list itself. Weaving each clone directly behind its original means original.next is the lookup table, so random.next finds the cloned target with no dictionary at all. Whenever you need an old-to-new association, ask whether the structure can hold it for you.
Approach
Pass 1 — interleave
After each original node insert its clone: A→A'→B→B'. Clones are reachable from their originals in O(1).
Pass 2 — wire randoms
For each original cur, its clone's random is cur.random.next (the clone of cur.random). Nulls pass through.
Pass 3 — unweave
Split the interleaved list back into original and copy, restoring the original intact.
Solution & live demo
Common pitfalls
Copying the random pointers in the same pass as the clones
while cur:
cur.next = Node(cur.val, cur.next)
cur.next.random = cur.random.next
cur = cur.next.next# pass 1: weave clones # pass 2: wire randoms # pass 3: unweave
A random pointer can target a node further along that hasn't been cloned yet, so cur.random.next is still the original's neighbour rather than its clone. Every clone must exist before any random is wired — that's why the passes can't merge.
Dereferencing a null random
cur.next.random = cur.random.next
if cur.random:
cur.next.random = cur.random.nextRandom is allowed to be null, and None.next raises. A clone's random defaults to null already, so the guard simply skips the assignment.
Not restoring the original list
return head.next
while cur:
clone = cur.next
cur.next = clone.next
clone.next = clone.next.next if clone.next else None
cur = cur.nextLeaving the two lists interleaved means the input is returned corrupted — every original node points at a clone. The third pass separates them, and the trailing null check stops the last clone from dereferencing past the end.
Edge cases
Guard: only assign when cur.random exists.
cur.random.next is the node's own clone — works unchanged.