You are given a special linked list with n nodes where each node has two pointers a next pointer that points to the next node of the singly linked list, and a random pointer that points to the random node of the linked list.
Construct a copy of this linked list. The copy should consist of the same number of new nodes, where each new node has the value corresponding to its original node. Both the next and random pointer of the new nodes should point to new nodes in the copied list, such that it also represent the same list state. None of the pointers in the new list should point to nodes in the original list.
Return the head of the copied linked list.
NOTE : Original linked list should remain unchanged.
Examples:
Input: head = [[1, 3], [3, 3], [5, NULL], [9, 3]]
![]()
Output: head = [[1, 3], [3, 3], [5, NULL], [9, 3]] Explanation: Node 1 points to Node 2 as its NEXT and Node 3 as its RANDOM. Node 2 points to Node 3 as its NEXT and Node 3 as its RANDOM. Node 3 points to Node 4 as its NEXT and NULL as its RANDOM. Node 4 points to NULL as its NEXT and Node 3 as its RANDOM.
Input: head = [[1, 3], [2, 1], [3, 5], [4, 3], [5, 2]]
Output: head = [[1, 3], [2, 1], [3, 5], [4, 3], [5, 2]] Explanation: Node 1 points to Node 2 as its NEXT and Node 3 as its RANDOM. Node 2 points to Node 3 as its NEXT and Node 1 as its RANDOM. Node 3 points to Node 4 as its NEXT and Node 5 as its RANDOM. Node 4 points to Node 5 as its NEXT and Node 3 as its RANDOM. Node 5 points to NULL as its NEXT and Node 2 as its RANDOM.
Input: head = [[7, NULL], [7, NULL]]
Output: head = [[7, NULL], [7, NULL]] Explanation: Node 1 points to Node 2 as its NEXT and NULL as its RANDOM. Node 2 points to NULL as its NEXT and NULL as its RANDOM.
Constraints:
1 <= n <= 100
0 <= node->data <= 1000
Approach 01:
-
C++
-
Python
class Solution {
public:
Node* copyList(Node* head) {
// Map to store the original node to its copy
unordered_map<Node*, Node*> nodeMap;
Node* currentNode = head;
// First pass: Create new nodes and store them in the map
while (currentNode) {
nodeMap[currentNode] = new Node(currentNode->data);
currentNode = currentNode->next;
}
currentNode = head;
// Second pass: Assign next and random pointers for the copied nodes
while (currentNode) {
nodeMap[currentNode]->next = currentNode->next ? nodeMap[currentNode->next] : nullptr;
nodeMap[currentNode]->random = currentNode->random ? nodeMap[currentNode->random] : nullptr;
currentNode = currentNode->next;
}
// Return the head of the copied list
return nodeMap[head];
}
};
class Solution:
def cloneLinkedList(self, head):
if head is None:
return None
# Step 1: Create copies of each node and link them in between original nodes
currentNode = head
while currentNode:
clonedNode = Node(currentNode.data)
clonedNode.next = currentNode.next
currentNode.next = clonedNode
currentNode = clonedNode.next
# Step 2: Set the random pointers for the cloned nodes
currentNode = head
while currentNode:
if currentNode.random:
currentNode.next.random = currentNode.random.next
currentNode = currentNode.next.next
# Step 3: Separate the original and cloned linked lists
originalNode = head
clonedHead = head.next
clonedNode = clonedHead
while originalNode:
originalNode.next = originalNode.next.next
if clonedNode.next:
clonedNode.next = clonedNode.next.next
originalNode = originalNode.next
clonedNode = clonedNode.next
return clonedHead
Time Complexity:
- First Pass:
Creating new nodes and storing them in the map involves iterating through the original linked list, taking \( O(n) \), where \( n \) is the number of nodes in the list.
- Second Pass:
Assigning the
nextandrandompointers for the copied nodes also takes \( O(n) \), as we iterate through the list again. - Overall Time Complexity:
The total time complexity is \( O(n) \).
Space Complexity:
- Hash Map:
The hash map stores one entry for each node in the original list, requiring \( O(n) \) space.
- Copied List:
The copied linked list requires \( O(n) \) space to store the new nodes.
- Overall Space Complexity:
The total space complexity is \( O(n) \).
