
Problem Statement
In this task, we have a unique data structure called a linked list where each node not only points to the next node in sequence via the next
pointer, but also has an additional random
pointer. This random
pointer can link to any node within the list (or to none at all, i.e., null
).
The challenge stems from needing to create a deep copy of this linked list. A deep copy involves generating entirely new nodes that replicate the value
and the pattern of next
and random
connections of the original list. Unlike a shallow copy, where the copy might still contain references to original pieces, each node and linkage in a deep copy stands alone and independent of the original dataset.
This problem calls for precision in handling pointers, particularly ensuring that the new list's random
pointers correlate directly with the new corresponding nodes, not the initial ones. Therefore, the outcome should maintain both the sequence (next
pointers) and the random
relationships, without retaining any references to the original list nodes.
Examples
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]]
Example 3
Input:
head = [[3,null],[3,0],[3,null]]
Output:
[[3,null],[3,0],[3,null]]
Constraints
0 <= n <= 1000
-104 <= Node.val <= 104
Node.random
isnull
or is pointing to some node in the linked list.
Approach and Intuition
To tackle the problem of creating a deep copy of a linked list with both next
and random
pointers, consider the following approach, drawn from the provided examples and constraints:
Iterative Relation Establishment with Mapping:
- Initialize a hashmap to track and relate original nodes to their respective clones. This data structure will expedite access and prevent the recreation of already copied nodes.
- Traverse the original linked list. For each node, create a clone and add it to the hashmap.
- On this first pass, only establish the
next
pointers for the clones using the hashmap to prevent the lingering dependency on original nodes. - In a subsequent traversal, set up the
random
pointers for each cloned node. Use the hashmap to translate the random pointers from the original to the corresponding cloned nodes accurately.
Edge Cases Handling:
- For lists of length
n = 0
, simply returnnull
as there are no nodes to copy. - For the random pointer, ensure each cloned
random
pointer maps correctly even if the original pointer isnull
.
- For lists of length
Efficiency Considerations:
- Given the constraint (
0 <= n <= 1000
), creating a structure of one hashmap and two full list traversals should remain computationally reasonable. - Directly read and establish connections in two separate passes to avoid complications or corruptions, such as prematurely linking clones or inadvertently contiguous assignments.
- Given the constraint (
This approach, by accurately using an auxiliary hashmap and ensuring comprehensiveness in node linkage assignment, encapsulates an efficient and error-resistant method to achieve the deep copy of a complex linked list.
Solutions
- C++
- Java
- C
- JavaScript
- Python
class Solution {
public:
Node* cloneListWithRandomPointer(Node* original_head) {
if (!original_head) {
return nullptr;
}
Node* current = original_head;
while (current != nullptr) {
Node* clone = new Node(current->val, nullptr, nullptr);
clone->next = current->next;
current->next = clone;
current = clone->next;
}
current = original_head;
while (current != nullptr) {
current->next->random = current->random ? current->random->next : nullptr;
current = current->next->next;
}
Node* old_list = original_head;
Node* new_list = original_head->next;
Node* new_head = original_head->next;
while (old_list != nullptr) {
old_list->next = old_list->next->next;
new_list->next = new_list->next ? new_list->next->next : nullptr;
old_list = old_list->next;
new_list = new_list->next;
}
return new_head;
}
};
This solution outlines how to clone a linked list where each node contains an additional pointer to a random node in the list. The function cloneListWithRandomPointer
implements this operation in C++. Here’s a breakdown of the method used:
- Firstly, traverse the original linked list to create a new node for each existing node. Insert these new nodes directly after their corresponding original nodes.
- Next, assign the
random
pointer of each new node. This is done by setting it to therandom
pointer of the original node's next node, taking care to check if the original node'srandom
pointer is null. - Finally, separate the interleaved list of original and new nodes. This involves correcting the
next
pointers of both the original and the copied nodes to restore the original list and to finish forming the separate cloned list.
The outcome is a new linked list where each node from the original list is duplicated with both the next
and random
pointers correctly assigned, effectively deep copying the initial list with its random pointer structure intact.
Ensure following this explanation allows for an understanding of manipulating complex data structures, such as linked lists with additional pointer tracking.
public class Solution {
public Node cloneRandomLinkedList(Node originalHead) {
if (originalHead == null) {
return null;
}
Node current = originalHead;
while (current != null) {
Node clonedNode = new Node(current.val);
clonedNode.next = current.next;
current.next = clonedNode;
current = clonedNode.next;
}
current = originalHead;
while (current != null) {
current.next.random = (current.random != null) ? current.random.next : null;
current = current.next.next;
}
Node originalCurrent = originalHead;
Node clonedCurrent = originalHead.next;
Node clonedHead = originalHead.next;
while (originalCurrent != null) {
originalCurrent.next = originalCurrent.next.next;
clonedCurrent.next = (clonedCurrent.next != null)
? clonedCurrent.next.next
: null;
originalCurrent = originalCurrent.next;
clonedCurrent = clonedCurrent.next;
}
return clonedHead;
}
}
The provided Java code defines a method cloneRandomLinkedList
within the Solution
class, which is designed to clone a complex linked list where each node has a next
pointer and a random pointer. The task involves deep copying a list such that the new list is a standalone copy of the original list with the same val
, next
, and random
connections.
Below is the step-by-step approach taken in the code to accomplish this:
- The method first checks if the input head node,
originalHead
, is null. If it is, it returns null indicating there are no nodes to duplicate. - Define
current
to traverse the original list. Iterate through the list:- Create a new node,
clonedNode
, for each original node mirroring theval
. - Insert the cloned node just after the original node by adjusting the
next
pointers, effectively weaving the cloned nodes among the original nodes.
- Create a new node,
- Set
current
back tooriginalHead
to start the second pass through the list:- Assign the
random
pointer of each cloned node. This is achieved by pointing it to thenext
of therandom
pointed node of the original, if therandom
pointer is not null.
- Assign the
- Initialize pointers to handle separation of the original and cloned list:
originalCurrent
points to the beginning of the intertwined list.clonedCurrent
andclonedHead
point to the head of the cloned list.
- Decouple the original and cloned lists:
- Advance
originalCurrent
andclonedCurrent
through their respective lists resetting thenext
pointers to restore the original list and to finalize the separate cloned list.
- Advance
This method uses space efficiently by avoiding the use of extra space for a map typically used to keep track of cloned nodes vis-a-vis their corresponding original nodes. The node intertwining and later separation technique ensures both lists are properly set up with correct pointers, all within a linear time complexity relative to the number of nodes in the original list.
struct Node* createNode(int value, struct Node* nextNode, struct Node* randomPointer) {
struct Node* tempNode = (struct Node*)malloc(sizeof(struct Node));
tempNode->val = value;
tempNode->next = nextNode;
tempNode->random = randomPointer;
return tempNode;
}
struct Node* cloneLinkedListWithRandomPointer(struct Node* originalHead) {
if (!originalHead) {
return NULL;
}
struct Node* traverse = originalHead;
while (traverse) {
struct Node* clonedNode = createNode(traverse->val, NULL, NULL);
clonedNode->next = traverse->next;
traverse->next = clonedNode;
traverse = clonedNode->next;
}
traverse = originalHead;
while (traverse) {
traverse->next->random = (traverse->random) ? traverse->random->next : NULL;
traverse = traverse->next->next;
}
struct Node* oldListPointer = originalHead;
struct Node* newListPointer = originalHead->next;
struct Node* clonedHead = originalHead->next;
while (oldListPointer) {
oldListPointer->next = oldListPointer->next->next;
newListPointer->next = (newListPointer->next) ? newListPointer->next->next : NULL;
oldListPointer = oldListPointer->next;
newListPointer = newListPointer->next;
}
return clonedHead;
}
The provided C code tackles the problem of duplicating a linked list where each node possesses an additional random pointer apart from the standard next pointer. The solution involves creating a deep copy of the list, ensuring that the random links between nodes are accurately reproduced in the new list.
The first function,
createNode
, is a helper function to initialize and allocate memory for a new node when given a value, a pointer to the next node, and a pointer to a random node.The main function,
cloneLinkedListWithRandomPointer
, begins by handling the edge case where the input list is empty, returningNULL
if so.Next, it loops through the original list, inserting a cloned node immediately after each original node. This is achieved by:
- Allocating a new node for each original node using
createNode
. - Adjusting
next
pointers to include the newly created clone node right after the original one.
- Allocating a new node for each original node using
Following the clone insertion, the code proceeds to assign the
random
pointers for each of the cloned nodes. It does this in a second traversal of the list, ensuring each cloned node'srandom
points to the subsequent node of its counterpart'srandom
pointer if it exists; otherwise, it is set toNULL
.Finally, the function extracts the cloned nodes to form a new list. It adjusts the
next
pointers of both original and cloned nodes:- Setting the original nodes'
next
to skip over their respective clones. - Connecting the cloned nodes to each other correctly based on the original sequence.
- Setting the original nodes'
The sequence of links adjustments ensures that the original list remains intact, and a new list that mirrors the structure and random connections of the original is returned.
The approach carefully handles memory management and pointer adjustments to create a cloned list, which exactly replicates the complicated connection schemas of the original.
var duplicateRandomList = function (origin) {
if (origin === null) {
return null;
}
let current = origin;
while (current !== null) {
let copied = new Node(current.val, null, null);
copied.next = current.next;
current.next = copied;
current = copied.next;
}
current = origin;
while (current !== null) {
current.next.random = current.random !== null ? current.random.next : null;
current = current.next.next;
}
let oldList = origin; // Original nodes list
let newList = origin.next; // Copied nodes list
let savedHead = origin.next;
while (oldList !== null) {
oldList.next = oldList.next.next;
newList.next = newList.next !== null ? newList.next.next : null;
oldList = oldList.next;
newList = newList.next;
}
return savedHead;
};
This JavaScript solution addresses the problem of duplicating a linked list where each node has a next
pointer and a random
pointer that can point to any node in the list or null
.
Here's a breakdown of how the solution works:
First, check if the input list,
origin
, isnull
. If it is, returnnull
since there is no list to copy.Iterate through the original list and for each node, create a new node with the same value. Insert these new nodes right after their corresponding original nodes. This interleaving of old and new nodes helps keep track of the random pointers in the subsequent steps.
Once the new nodes are inserted, iterate through the list again to update the
random
pointers of the new nodes. For each original node'srandom
pointer, point the corresponding new node'srandom
to the new node of the original random's target. This step effectively clones the random linkage between nodes.Separate the interleaved list into the original list and the copied list. Initialize two pointers,
oldList
for traversing the original nodes, andnewList
for traversing the new nodes. Adjust thenext
pointers for both lists to extract the copied list while restoring the original list's structure.Finally, return the head of the new list,
savedHead
, which is a fully duplicated list mirroring the original list with bothnext
andrandom
pointers correctly set.
This approach efficiently clones the list in linear time complexity with constant space complexity, making it a robust solution for duplicating linked lists with complex internal linkages.
class Solution:
def duplicateRandomList(self, head: "Optional[Node]") -> "Optional[Node]":
if not head:
return head
# Creating intertwining of old and duplicated nodes
current = head
while current:
# Create duplicate node
duplicate = Node(current.val, None, None)
# Place the duplicate node beside the original
duplicate.next = current.next
current.next = duplicate
current = duplicate.next
current = head
# Set the 'random' pointer for the duplicate nodes
while current:
current.next.random = current.random.next if current.random else None
current = current.next.next
# Decouple the two interleaved linked lists
old_ptr = head # Original nodes path
dup_ptr = head.next # Duplicated nodes path
dup_head = head.next
while old_ptr:
old_ptr.next = old_ptr.next.next
dup_ptr.next = dup_ptr.next.next if dup_ptr.next else None
old_ptr = old_ptr.next
dup_ptr = dup_ptr.next
return dup_head
This Python function efficiently duplicates a linked list where each node contains an additional random pointer that might point to any node within the list or be null
. The strategy implemented here involves three main steps:
Interweave the original list with cloned nodes:
- Traverse the original list and create a new node for each existing node.
- Insert each new node directly after its corresponding original node, modifying the
next
pointers accordingly.
Establish correct
random
pointers for the cloned nodes:- Again traverse the list. For each original node's cloned node, set the
random
pointer by using the original node'srandom
pointer. - The key is to assign the cloned
random
pointer to point to the next node of the originalrandom
pointer. This handles cases whether the originalrandom
pointer isnull
.
- Again traverse the list. For each original node's cloned node, set the
Separating the intertwined lists into two independent lists:
- Initialize two pointers, one for the original list and one for the clone, then iterate through the intertwined list, appropriately adjusting the
next
pointers to decouple the original nodes from their clones.
- Initialize two pointers, one for the original list and one for the clone, then iterate through the intertwined list, appropriately adjusting the
During this entire procedure, the function ensures that the structural integrity of the original list is maintained, and each cloned node is correctly linked, both through the next
and random
pointers. The function returns the head of the copied list, which facilitates further operations on the duplicated structure without affecting the original list. This in-place solution adds efficiency in terms of space, working without the need for additional data structures for mapping old nodes to their duplicates.
No comments yet.