A linked list is given such that each node contains an additional random pointer, which could point to any node in the list, or null.
Construct a deep copy of the list. The deep copy should consist of exactly n brand new nodes, where each new node has its value set to the value of its corresponding original node. Both the next and random pointer of the new nodes should point to new nodes in the copied list such that the pointers in the original list and copied list represent the same list state. None of the pointers in the new list should point to nodes in the original list.
For example, if there are two nodes X and Y in the original list, where X.random --> Y, then for the corresponding two nodes x and y in the copied list, x.random --> y.
Return the head of the copied linked list.
Example 1:
Input: head = [[7,null],[13,0],[11,4],[10,2],[1,0]] Output: [[7,null],[13,0],[11,4],[10,2],[1,0]]
Example 2:
Input: head = [[1,1],[2,1]] Output: [[1,1],[2,1]]
Can you provide a solution with O(1) space complexity?
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
We want to create an exact duplicate of a linked list, but this list has a twist: each item can point to any other item in the list randomly. The brute force way to do this is to painstakingly rebuild the list item by item, making sure each item in the copy has the same relationships as the original.
Here's how the algorithm would work step-by-step:
class Node:
def __init__(self, value):
self.value = value
self.next = None
self.random = None
def copy_list_with_random_pointer_brute_force(head):
if not head:
return None
# Create a dictionary to store the mapping between original nodes and copied nodes
original_to_copy_map = {}
# First pass: Create new nodes with the same values as the original list
current_node = head
while current_node:
copy_node = Node(current_node.value)
original_to_copy_map[current_node] = copy_node
current_node = current_node.next
# Second pass: Set the next and random pointers of the new nodes
current_node = head
while current_node:
copy_node = original_to_copy_map[current_node]
# Set the next pointer of the copy node
if current_node.next:
copy_node.next = original_to_copy_map[current_node.next]
# Now handle the random pointers
if current_node.random:
copy_node.random = original_to_copy_map[current_node.random]
current_node = current_node.next
# Return the head of the copied list
return original_to_copy_map[head]
To create a perfect copy, we use a clever trick to avoid repeated lookups. We first weave the copy into the original list, then fix the 'random' connections, and finally separate the copy from the original.
Here's how the algorithm would work step-by-step:
class Node:
def __init__(self, value):
self.value = value
self.next = None
self.random = None
def copy_list_with_random_pointer(head):
if not head:
return None
current_node = head
# Interweave copied nodes within the original list.
while current_node:
copied_node = Node(current_node.value)
copied_node.next = current_node.next
current_node.next = copied_node
current_node = copied_node.next
current_node = head
# Assign random pointers for the copied nodes.
while current_node:
if current_node.random:
current_node.next.random = current_node.random.next
current_node = current_node.next.next
current_node = head
copied_head = head.next
copied_node = copied_head
# Separate the copied list from the original list.
while current_node:
current_node.next = current_node.next.next
if copied_node.next:
copied_node.next = copied_node.next.next
current_node = current_node.next
copied_node = copied_node.next
return copied_head
Case | How to Handle |
---|---|
Null or empty input list | Return null immediately as there's nothing to copy. |
Single node list | The solution should correctly copy the single node and its random pointer (which might be null or point to itself). |
List with all random pointers being null | The copied list should also have all random pointers as null. |
List where all random pointers point to the same node | The copied list should have all random pointers pointing to the copied version of that node. |
Random pointer creates a cycle within the original list | The copying mechanism should not enter an infinite loop and must correctly handle the cyclic random pointer. |
Large list to test memory usage and performance | The solution should be memory efficient, ideally O(n) space, and should avoid stack overflow issues in recursive implementations by using iterative approaches. |
Random pointer points to itself | The copy's random pointer should point to the copy of the node itself. |
Original list is modified during the copying process (though not usually expected in interview context). | The copying process should be independent of modifications to the original list during its execution, which suggests making a complete copy right away. |