Skip to content

Commit

Permalink
UTSAVS26#881 added clone linked list
Browse files Browse the repository at this point in the history
Clone a linked list where each node has a next pointer and a random pointer that can reference any node or be None.
  • Loading branch information
SKG24 committed Oct 28, 2024
1 parent d9c978f commit 96df090
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
self.random = None

# Function to clone the linked list with random pointers
def clone_linked_list_with_random_pointer(head):
if not head:
return None

# Step 1: Create a dictionary to store the mapping from original to cloned nodes
node_map = {}

# Step 2: First pass to create all nodes (without setting next or random)
curr = head
while curr:
node_map[curr] = ListNode(curr.val) # Map original node to its clone
curr = curr.next

# Step 3: Second pass to set next and random pointers
curr = head
while curr:
node_map[curr].next = node_map.get(curr.next) # Set the next pointer
node_map[curr].random = node_map.get(curr.random) # Set the random pointer
curr = curr.next

# Return the head of the cloned list
return node_map[head]

# Helper function to create a linked list from a list of values and random indices
def create_linked_list(values, random_indices):
if not values:
return None

# Create all nodes
nodes = [ListNode(val) for val in values]

# Set the next pointers
for i in range(len(nodes) - 1):
nodes[i].next = nodes[i + 1]

# Set the random pointers based on random_indices
for i, random_index in enumerate(random_indices):
if random_index != -1: # -1 indicates no random pointer
nodes[i].random = nodes[random_index]

return nodes[0]

# Helper function to print the linked list along with random pointers
def print_linked_list(head):
curr = head
while curr:
random_val = curr.random.val if curr.random else "NULL"
print(f"Node({curr.val}) -> Random({random_val})")
curr = curr.next

# Main function to demonstrate cloning
if __name__ == "__main__":
# Define values and random indices for each node
values = [1, 2, 3, 4, 5]
random_indices = [2, 4, -1, 0, 1] # -1 indicates no random pointer

# Create the linked list with random pointers
original_list = create_linked_list(values, random_indices)

print("Original list with random pointers:")
print_linked_list(original_list)

# Clone the linked list
cloned_list = clone_linked_list_with_random_pointer(original_list)

print("\nCloned list with random pointers:")
print_linked_list(cloned_list)
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Clone a Linked List with Random Pointers

## Problem Statement

Given a linked list where each node contains:
- An integer `val`.
- A `next` pointer to the next node in the list.
- A `random` pointer that points to any node in the list or is `NULL`.

The task is to **create a deep copy (clone) of this linked list**. The cloned list should have the same values, `next`, and `random` pointer connections as the original list but should not share any nodes with it.

## Example

Consider a linked list where:
- Node values: `[1, 2, 3, 4, 5]`
- Random pointers map as follows:
- `1`'s random points to `3`
- `2`'s random points to `5`
- `3` has no random pointer (`NULL`)
- `4`'s random points to `1`
- `5`'s random points to `2`

The structure of both the original and cloned list should look like this:

Original list: 1 -> 2 -> 3 -> 4 -> 5 | | | ↓ ↓ ↓ 3 5 1

Cloned list: 1' -> 2' -> 3' -> 4' -> 5' | | | ↓ ↓ ↓ 3' 5' 1'

## Solution Approach

1. **Mapping Original Nodes to Clones**: Use a dictionary to map each node in the original list to its corresponding cloned node, created based on its `val`.
2. **Setting Pointers**: Traverse the list a second time to set the `next` and `random` pointers for each cloned node.
3. **Return Cloned List**: Return the head of the cloned list.

## Steps to Solve

### Step 1: Mapping Original Nodes to Clones
- Use a dictionary (`node_map`) to store a mapping of each node in the original list to its clone, initially creating cloned nodes without setting `next` or `random` pointers.

### Step 2: Setting `next` and `random` Pointers
- Traverse the list again and set the `next` and `random` pointers for each cloned node using the `node_map` dictionary:
- **Next Pointer**: Map each node's `next` pointer to the corresponding clone.
- **Random Pointer**: Map each node's `random` pointer to the corresponding clone.

### Step 3: Return the Cloned Head
- Return the cloned head node from `node_map`.

## Code Walkthrough

1. **`clone_linked_list_with_random_pointer(head)`**: Clones the linked list using a dictionary to map each original node to its clone.
2. **`create_linked_list(values, random_indices)`**: Creates a linked list with given `values` and `random` pointers based on the indices in `random_indices`.
3. **`print_linked_list(head)`**: Helper function to print each node’s value and its `random` pointer, if any.


**Explanation of Complexity**
- Time Complexity: 𝑂(𝑛), where n is the number of nodes in the list. We traverse the list twice.
- Space Complexity: 𝑂(𝑛), due to the use of the hash map to store mappings from original to cloned nodes.

0 comments on commit 96df090

Please sign in to comment.