medium Copy List with Random Pointer
Problem Statement
You are given a linked list where each node contains an additional random pointer. This pointer could point to any node in the list or be null.
Create a deep copy of this linked list. The deep copy should have n new nodes, where each new node's value matches the value of its corresponding node in the original list. Additionally, both the next and random pointers of the new nodes should point to the new nodes in the copied list.
The pointers in the copied list should maintain the same structure as the original list. None of the pointers in the new list should reference any node in the original list.
For instance, if in the original list, node X has a random pointer to node Y (X.random -> Y), then in the copied list, the corresponding nodes x and y should have a random pointer such that x.random -> y.
The linked list is represented in the input/output as a list of n nodes. Each node is represented as a pair of [val, randomIndex] where:
val: It is an integer representing Node.valrandomIndex:The index of the node (range from0ton-1) that the random pointer points to, or null if it does not point to any node.
Given a head of the linked list, return the head of the newly copied linked list.
Examples
Example 1:
- Input: head =
[[3, 1], [4, null], [5, 0], [7, 2]]
- Output:
[[3, 1], [4, null], [5, 0], [7, 2]] - Explanation: The original list is cloned and returned.
Example 2:
- Input: head =
[[1, 2], [2, 0], [3, 1]]
- Expected Output:
[[1, 2], [2, 0], [3, 1]] - Explanation: The original list is cloned and returned.
Example 3:
- Input: head =
[[8, 2], [9, null], [7, 1]]
- Output:
[[8, 2], [9, null], [7, 1]] - Explanation: The original list is cloned and returned.
Constraints:
- 0 <= n <= 1000
- -104 <= Node.val <= 104
Node.randomis null or is pointing to some node in the linked list.
Try it yourself
Try solving this question here:
✅ Solution Copy List with Random Pointer
Problem Statement
You are given a linked list where each node contains an additional random pointer. This pointer could point to any node in the list or be null.
Create a deep copy of this linked list. The deep copy should have n new nodes, where each new node's value matches the value of its corresponding node in the original list. Additionally, both the next and random pointers of the new nodes should point to the new nodes in the copied list.
The pointers in the copied list should maintain the same structure as the original list. None of the pointers in the new list should reference any node in the original list.
For instance, if in the original list, node X has a random pointer to node Y (X.random -> Y), then in the copied list, the corresponding nodes x and y should have a random pointer such that x.random -> y.
The linked list is represented in the input/output as a list of n nodes. Each node is represented as a pair of [val, randomIndex] where:
val: It is an integer representing Node.valrandomIndex:The index of the node (range from0ton-1) that the random pointer points to, or null if it does not point to any node.
Given a head of the linked list, return the head of the newly copied linked list.
Examples
Example 1:
- Input: head =
[[3, 1], [4, null], [5, 0], [7, 2]]
- Output:
[[3, 1], [4, null], [5, 0], [7, 2]] - Explanation: The original list is cloned and returned.
Example 2:
- Input: head =
[[1, 2], [2, 0], [3, 1]]
- Expected Output:
[[1, 2], [2, 0], [3, 1]] - Explanation: The original list is cloned and returned.
Example 3:
- Input: head =
[[8, 2], [9, null], [7, 1]]
- Output:
[[8, 2], [9, null], [7, 1]] - Explanation: The original list is cloned and returned.
Constraints:
- 0 <= n <= 1000
- -104 <= Node.val <= 104
Node.randomis null or is pointing to some node in the linked list.
Solution
To solve this problem, we make three passes over the original linked list to create a deep copy that maintains the same next and random pointer structure as the original list. In the first pass, we insert a copy of each node right next to the original node. This helps us easily link the next pointers of the copied nodes. During the second pass, we set up the random pointers for the copied nodes using the established relationship between the original nodes and their copies. Finally, in the third pass, we separate the original and copied nodes, restoring the original list and forming the deep-copied list.
This approach is efficient because it only traverses the list three times, maintaining a linear time complexity of next and random pointers without additional data structures, making the solution space-efficient with
Step-by-Step Algorithm
-
Check for Empty List:
- If the input
headisnull, returnnull. This handles the edge case where the input list is empty.
- If the input
-
First Pass: Create and Insert Copied Nodes:
- Initialize a pointer
currentto theheadof the original list. - Traverse the list while
currentis notnull:- For each node (
current), create a new nodecopywith the same value (current.val). - Set the
nextpointer ofcopytocurrent.next. - Insert
copyright aftercurrentby settingcurrent.nexttocopy. - Move
currenttocopy.next(i.e., the next original node).
- For each node (
- Initialize a pointer
-
Second Pass: Set Random Pointers for Copied Nodes:
- Reinitialize
currentto theheadof the original list. - Traverse the list again while
currentis notnull:- If
current.randomis notnull, set therandompointer ofcurrent.next(the copied node) tocurrent.random.next(the copy of the nodecurrent.randompoints to). - Move
currenttocurrent.next.next(i.e., the next original node).
- If
- Reinitialize
-
Third Pass: Separate the Original and Copied Lists:
- Reinitialize
currentto theheadof the original list. - Initialize
copiedHeadtohead.next(the head of the copied list). - Use a pointer
copyto iterate over the copied list, initially set tocopiedHead. - Traverse the list while
currentis notnull:- Set
current.nexttocurrent.next.nextto restore the original list. - If
copy.nextis notnull, setcopy.nexttocopy.next.nextto form the copied list. This steps removes the node of the original list. - Move both
currentandcopyto their respectivenextnodes.
- Set
- Reinitialize
-
Return the Head of the Copied List:
- Return
copiedHead, which points to the head of the deep-copied linked list.
- Return
Algorithm Walkthrough
Let's walk through the algorithm using the input head = [[3, 1], [4, null], [5, 0], [7, 2]].
- Input Linked List:
- Node 1: Value
3, Random Pointer -> Node at index1(Node with value4) - Node 2: Value
4, Random Pointer ->null - Node 3: Value
5, Random Pointer -> Node at index0(Node with value3) - Node 4: Value
7, Random Pointer -> Node at index2(Node with value5)
- Node 1: Value
First Pass: Create and Insert Copied Nodes
-
Start with
currentat Node 1 (Value3):- Create
Node 1'(Value3). - Insert
Node 1'after Node 1:- The list becomes:
3 -> 3' -> 4 -> 5 -> 7.
- The list becomes:
- Move
currentto Node 2 (Value4).
- Create
-
At Node 2 (Value
4):- Create
Node 2'(Value4). - Insert
Node 2'after Node 2:- The list becomes:
3 -> 3' -> 4 -> 4' -> 5 -> 7.
- The list becomes:
- Move
currentto Node 3 (Value5).
- Create
-
At Node 3 (Value
5):- Create
Node 3'(Value5). - Insert
Node 3'after Node 3:- The list becomes:
3 -> 3' -> 4 -> 4' -> 5 -> 5' -> 7.
- The list becomes:
- Move
currentto Node 4 (Value7).
- Create
-
At Node 4 (Value
7):- Create
Node 4'(Value7). - Insert
Node 4'after Node 4:- The list becomes:
3 -> 3' -> 4 -> 4' -> 5 -> 5' -> 7 -> 7'.
- The list becomes:
- Move
currenttonull, ending the first pass.
- Create
Second Pass: Set Random Pointers for Copied Nodes
-
Start with
currentat Node 1 (Value3):current.randompoints to Node 2 (Value4).- Set
Node 1'.randomtoNode 2'.random:Node 3'.randomis now correctly set to Node 2'.
- Move
currentto Node 2 (Value4).
-
At Node 2 (Value
4):current.randomisnull.Node 2'.randomremainsnull.- Move
currentto Node 3 (Value5).
-
At Node 3 (Value
5):current.randompoints to Node 1 (Value3).- Set
Node 3'.randomtoNode 1'.random:Node 3'.randomis now correctly set to Node 1'.
- Move
currentto Node 4 (Value7).
-
At Node 4 (Value
7):current.randompoints to Node 3 (Value5).- Set
Node 4'.randomtoNode 3'.random:Node 4'.randomis now correctly set to Node 3'.
- Move
currenttonull, ending the second pass.
Third Pass: Separate the Original and Copied Lists
-
Start with
currentat Node 1 (Value3),copiedHeadat Node 1' (Value3), andcopyat Node 1'.- Set
current.nextto Node 2 (restoring the original list). - Set
copy.nextto Node 2'. - Move
currentto Node 2 andcopyto Node 2'.
- Set
-
At Node 2 (Value
4):- Set
current.nextto Node 3 (restoring the original list). - Set
copy.nextto Node 3'. - Move
currentto Node 3 andcopyto Node 3'.
- Set
-
At Node 3 (Value
5):- Set
current.nextto Node 4 (restoring the original list). - Set
copy.nextto Node 4'. - Move
currentto Node 4 andcopyto Node 4'.
- Set
-
At Node 4 (Value
7):- Set
current.nexttonull(restoring the original list). - Set
copy.nexttonull. - Move
currenttonullandcopytonull, ending the third pass.
- Set
Final Output
- Copied List:
3' -> 4' -> 5' -> 7', with correctnextandrandompointers.
- Original List remains unchanged:
3 -> 4 -> 5 -> 7.
Code
// Definition for a ListNode in the linked list
// class ListNode {
// int val;
// ListNode next;
// ListNode random;
// public ListNode(int val) {
// this.val = val;
// this.next = null;
// this.random = null;
// }
// }
public class Solution {
// Method to create a deep copy of a linked list with random pointers
public ListNode copyRandomList(ListNode head) {
if (head == null) return null; // If the original list is empty, return null
// Step 1: Create the copied nodes and insert them next to their originals
ListNode current = head;
while (current != null) {
ListNode copy = new ListNode(current.val); // Create a new node (deep copy)
// original linked list: A->B->C.
// Updated linked list A->A'->B->B'->C->C.
copy.next = current.next; // Set the next of the new node
current.next = copy; // Link the new node after the original node
current = copy.next; // Move to the next original node
}
// Step 2: Assign random pointers for the copied nodes
current = head;
while (current != null) {
if (current.random != null) {
current.next.random = current.random.next; // Set the random pointer for the copied node
}
current = current.next.next; // Move to the next original node
}
// Step 3: Separate the original list from the copied list
// i.e. A->A'->B->B'->C->C' would be broken to A->B->C and A'->B'->C'
current = head;
ListNode copiedHead = head.next; // Head of the copied linked list
ListNode copy = copiedHead;
while (current != null) {
current.next = current.next.next; // Restore the original list
if (copy.next != null) {
copy.next = copy.next.next; // Set the next for the copied list
}
current = current.next; // Move to the next original node
copy = copy.next; // Move to the next copied node
}
return copiedHead; // Return the head of the copied linked list
}
// Helper method to print the list for testing
public void printList(ListNode head) {
ListNode current = head;
while (current != null) {
int randomVal = (current.random != null) ? current.random.val : -1; // Get the random value or -1 if null
System.out.print("ListNode value: " + current.val + ", Random points to: " + randomVal + " | ");
current = current.next;
}
System.out.println();
}
public static void main(String[] args) {
Solution solution = new Solution();
// Example 1: Constructing the list [[3, 1], [4, null], [5, 0], [7, 2]]
ListNode node1 = new ListNode(3);
ListNode node2 = new ListNode(4);
ListNode node3 = new ListNode(5);
ListNode node4 = new ListNode(7);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node1.random = node2; // ListNode with value 3 has a random pointer to node with value 4
node2.random = null; // ListNode with value 4 has a random pointer to null
node3.random = node1; // ListNode with value 5 has a random pointer to node with value 3
node4.random = node3;
// Print the original list
System.out.println("Original List:");
solution.printList(node1);
// Create a deep copy of the list
ListNode copiedHead = solution.copyRandomList(node1);
// Print the copied list
System.out.println("Copied List:");
solution.printList(copiedHead);
}
}
Complexity Analysis
Time Complexity
The time complexity of the solution is n is the number of nodes in the linked list. This is because we perform three passes over the list:
- The first pass creates a copy of each node and inserts it immediately after the original node, taking
time. - The second pass sets the
randompointers for the copied nodes, which also takestime. - The third pass separates the original and copied lists, which again requires
time. Thus, the total time complexity is .
Space Complexity
The space complexity is
🤖 Don't fully get this? Learn it with Claude
Stuck on Copy List with Random Pointer? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Progressively stronger hints — you still solve it.
I'm working on the problem **Copy List with Random Pointer** (DSA). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
See the technique, not just code.
Explain the optimal approach to **Copy List with Random Pointer** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Catch bugs, edge cases, sub-optimality.
I'll paste my solution to **Copy List with Random Pointer**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Lock in recognition with look-alikes.
Give me 2 problems that use the SAME underlying pattern as **Copy List with Random Pointer**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.