DEV Community

Jaspreet singh
Jaspreet singh

Posted on

Copy List with Random Pointer

This problem is a classic Linked List interview question that tests your understanding of deep copying and pointer manipulation.

The challenge is not copying the next pointers, but correctly maintaining the relationships created by the random pointers.


Problem Statement

Given a linked list where each node contains:

int val;
Node next;
Node random;
Enter fullscreen mode Exit fullscreen mode

Create a deep copy of the list.

The copied list should:

  • Contain completely new nodes.
  • Preserve the next relationships.
  • Preserve the random relationships.
  • Not reference any node from the original list.

Brute Force Intuition

For every original node:

  • Create a copy node.
  • Store mapping:
Original Node -> Copied Node
Enter fullscreen mode Exit fullscreen mode

using a HashMap.

After creating all nodes:

  • Traverse again.
  • Connect next pointers.
  • Connect random pointers using the map.

Interview Explanation

Since random pointers can point anywhere in the list, we first create a clone of every node and store the original-to-copy mapping in a HashMap. During a second traversal, we use this mapping to connect both next and random pointers correctly.

Complexity

Time  : O(n)

Space : O(n)
Enter fullscreen mode Exit fullscreen mode

Moving Towards the Optimal Solution

Can we avoid the HashMap?

Notice:

Original:
A -> B -> C
Enter fullscreen mode Exit fullscreen mode

What if we insert cloned nodes in between?

A -> A' -> B -> B' -> C -> C'
Enter fullscreen mode Exit fullscreen mode

Now every clone sits immediately after its original node.

This creates a shortcut that allows us to assign random pointers without a HashMap.


Key Observation

Suppose:

A.random = C
Enter fullscreen mode Exit fullscreen mode

After inserting clones:

A -> A' -> B -> B' -> C -> C'
Enter fullscreen mode Exit fullscreen mode

Then:

A'.random = C'
Enter fullscreen mode Exit fullscreen mode

And:

C' = A.random.next
Enter fullscreen mode Exit fullscreen mode

Therefore:

copy.random = original.random.next;
Enter fullscreen mode Exit fullscreen mode

This is the entire trick behind the optimal solution.


Optimal Approach

Step 1

Insert cloned nodes between originals.

A -> A' -> B -> B' -> C -> C'
Enter fullscreen mode Exit fullscreen mode

Step 2

Assign random pointers.

copy.random = original.random.next;
Enter fullscreen mode Exit fullscreen mode

Step 3

Separate both lists.

Original:

A -> B -> C
Enter fullscreen mode Exit fullscreen mode

Copied:

A' -> B' -> C'
Enter fullscreen mode Exit fullscreen mode

Dry Run

Original List

1 -> 2 -> 3

1.random -> 3
2.random -> 1
3.random -> 2
Enter fullscreen mode Exit fullscreen mode

After Inserting Copies

1 -> 1' -> 2 -> 2' -> 3 -> 3'
Enter fullscreen mode Exit fullscreen mode

Setting Random Pointers

1'.random = 3'
2'.random = 1'
3'.random = 2'
Enter fullscreen mode Exit fullscreen mode

using:

cur.next.random = cur.random.next;
Enter fullscreen mode Exit fullscreen mode

Separate Lists

Original:

1 -> 2 -> 3
Enter fullscreen mode Exit fullscreen mode

Copied:

1' -> 2' -> 3'
Enter fullscreen mode Exit fullscreen mode

Deep copy created successfully.


Optimal Java Solution

class Solution {

    public Node copyRandomList(Node head) {

        if (head == null)
            return null;

        // Step 1: Insert copied nodes
        Node cur = head;

        while (cur != null) {

            Node copy = new Node(cur.val);

            copy.next = cur.next;
            cur.next = copy;

            cur = copy.next;
        }

        // Step 2: Set random pointers
        cur = head;

        while (cur != null) {

            if (cur.random != null) {
                cur.next.random = cur.random.next;
            }

            cur = cur.next.next;
        }

        // Step 3: Separate original and copied list
        Node dummy = new Node(0);
        Node copyTail = dummy;

        cur = head;

        while (cur != null) {

            Node copy = cur.next;

            cur.next = copy.next;

            copyTail.next = copy;
            copyTail = copy;

            cur = cur.next;
        }

        return dummy.next;
    }
}
Enter fullscreen mode Exit fullscreen mode

Why This Works

By inserting each copied node immediately after its original node:

Original -> Copy
Enter fullscreen mode Exit fullscreen mode

we can access the copied version of any node in O(1) time using:

original.next
Enter fullscreen mode Exit fullscreen mode

This removes the need for a HashMap entirely.


Complexity Analysis

Time  : O(n)

Space : O(1)
Enter fullscreen mode Exit fullscreen mode

No extra HashMap is used.


Pattern Recognition

Whenever you see:

  • Clone Linked List
  • Random Pointer
  • Deep Copy Structure

Think:

Interweave Copies
→ Set Random Pointers
→ Separate Lists
Enter fullscreen mode Exit fullscreen mode

This is the standard optimal interview pattern.


Interview One-Liner

Instead of using a HashMap, I interleave cloned nodes with original nodes, use the adjacency relationship to assign random pointers in O(1), and finally separate the two lists, achieving O(n) time and O(1) extra space.

Top comments (0)