Problem Overview
This problem is an extension of the classic linked list cloning problem. Along with the usual next pointer, every node also contains a random pointer that can point to any node in the list or be null.
Our task is to create a deep copy of the entire linked list.
A deep copy means:
- Every node in the new list is a completely new object.
- The
nextpointers should preserve the original ordering. - The
randompointers should point to the corresponding copied nodes—not the original ones.
Example
Original List:
A(3) ──► B(7) ──► C(4) ──► D(5)
| | | |
↓ ↓ ↓ ↓
null D A BThe copied list should have the exact same structure:
A'(3) ──► B'(7) ──► C'(4) ──► D'(5)
| | | |
↓ ↓ ↓ ↓
null D' A' B'Notice that every pointer in the copied list points only to copied nodes.
Key Observation
The biggest challenge is the random pointer.
While copying a node, we don’t necessarily know whether the node pointed to by random has already been copied.
For example:
1 -> 2 -> 3
1.random -> 3When copying node 1, node 3 may not have been copied yet.
So we need a way to quickly find the copied version of any original node.
This naturally suggests using a hash map.
Idea
Maintain a dictionary that maps:
Original Node ---> Copied NodeFor every node in the original list, we store its corresponding clone.
oldToCopy = {
original_node1 : copy_node1,
original_node2 : copy_node2,
...
}Once this mapping exists, assigning both next and random becomes straightforward.
Why
None
is Added to the Dictionary
One small but elegant trick is:
oldToCopy = {None: None}Why?
Some nodes may have
next = Noneor
random = NoneInstead of writing special cases like
if cur.random:
copy.random = oldToCopy[cur.random]
else:
copy.random = Nonewe can simply write
copy.random = oldToCopy[cur.random]because
oldToCopy[None] = NoneThis keeps the code clean and avoids unnecessary conditionals.
First Pass: Copy Every Node
We first create a copy of every node without connecting anything.
cur = head
while cur:
copy = Node(cur.val)
oldToCopy[cur] = copy
cur = cur.nextAt the end of this pass, we have:
Original: A -> B -> C
Dictionary:
A -> A'
B -> B'
C -> C'But none of the pointers have been assigned yet.
Second Pass: Connect the Pointers
Now every copied node already exists.
So we can safely connect both next and random.
cur = head
while cur:
copy = oldToCopy[cur]
copy.next = oldToCopy[cur.next]
copy.random = oldToCopy[cur.random]
cur = cur.nextSuppose
Original
A.random -> C
A.next -> BUsing the dictionary,
copy.random = oldToCopy[C] = C'
copy.next = oldToCopy[B] = B'Everything is connected correctly.
Dry Run
Consider:
1 -> 2 -> 3
1.random -> 3
2.random -> 1
3.random -> 2Pass 1
Create copies.
Dictionary
1 -> 1'
2 -> 2'
3 -> 3'Pass 2
For node 1:
1'.next = 2'
1'.random = 3'For node 2:
2'.next = 3'
2'.random = 1'For node 3:
3'.next = None
3'.random = 2'The copied list now perfectly mirrors the original.
Complete Solution
from typing import Optional
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: 'Optional[Node]') -> 'Optional[Node]':
oldToCopy = {None: None}
cur = head
# First pass: create copies
while cur:
copy = Node(cur.val)
oldToCopy[cur] = copy
cur = cur.next
cur = head
# Second pass: assign next and random pointers
while cur:
copy = oldToCopy[cur]
copy.next = oldToCopy[cur.next]
copy.random = oldToCopy[cur.random]
cur = cur.next
return oldToCopy[head]Complexity Analysis
Time Complexity
- First traversal: O(n)
- Second traversal: O(n)
Overall:
O(n)Space Complexity
The hash map stores one copied node for every original node.
O(n)Why This Approach Works
The core idea is to separate node creation from pointer assignment.
- Pass 1 ensures every copied node already exists.
- Pass 2 uses the hash map to connect
nextandrandompointers in constant time.
This avoids complicated forward references and keeps the implementation simple, readable, and efficient.
This is one of the cleanest solutions to the problem and is the standard hash map approach for cloning a linked list with random pointers.