Skip to content

Commit 86b183a

Browse files
committed
Add problem 138 - Copy List With Random Pointer
1 parent 8ba5297 commit 86b183a

File tree

4 files changed

+138
-1
lines changed

4 files changed

+138
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from typing import Optional
2+
3+
from problems.util.list_node_with_random import ListNodeWithRandom
4+
5+
6+
class CopyListWithRandomPointer:
7+
@staticmethod
8+
def copyRandomList(head: 'Optional[ListNodeWithRandom]') -> 'Optional[ListNodeWithRandom]':
9+
# Special case
10+
if head is None:
11+
return None
12+
# Dictionary to store the mappings of original and clone list
13+
mappings = {}
14+
# Head of the cloned list
15+
clone = None
16+
# Pointers to traverse the list
17+
temp, clone_temp = head, None
18+
# Traverse the list
19+
while temp is not None:
20+
# Create a cloned node
21+
copy = ListNodeWithRandom(temp.val)
22+
if clone is None:
23+
clone = copy
24+
clone_temp = clone
25+
else:
26+
clone_temp.next = copy
27+
clone_temp = clone_temp.next
28+
# Add the mapping
29+
mappings[temp] = clone_temp
30+
temp = temp.next
31+
# Reset temp pointers
32+
temp, clone_temp = head, clone
33+
while temp is not None:
34+
if temp.random is not None:
35+
clone_temp.random = mappings[temp.random]
36+
temp = temp.next
37+
clone_temp = clone_temp.next
38+
return clone

problems/util/list_node.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
class ListNode:
22
def __init__(self, val=0, next=None):
33
self.val = val
4-
self.next = next
4+
self.next = next
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class ListNodeWithRandom:
2+
def __init__(self, val=0, next=None, random=None):
3+
self.val = val
4+
self.next = next
5+
self.random = random
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import unittest
2+
3+
from problems.linked_list.copy_list_with_random_pointer import CopyListWithRandomPointer
4+
from problems.util.list_node_with_random import ListNodeWithRandom
5+
6+
7+
class CopyListWithRandomPointerTest(unittest.TestCase):
8+
9+
@staticmethod
10+
def list_to_array(head):
11+
"""Helper method to convert a list to an array representation for easier assertions."""
12+
array = []
13+
random_indices = []
14+
temp = head
15+
index_map = {}
16+
index = 0
17+
while temp:
18+
array.append(temp.val)
19+
index_map[temp] = index
20+
temp = temp.next
21+
index += 1
22+
temp = head
23+
while temp:
24+
if temp.random:
25+
random_indices.append(index_map[temp.random])
26+
else:
27+
random_indices.append(None)
28+
temp = temp.next
29+
return array, random_indices
30+
31+
def test_copy_random_list_empty(self):
32+
"""Test copying an empty list."""
33+
self.assertIsNone(CopyListWithRandomPointer.copyRandomList(None))
34+
35+
def test_copy_random_list_single_node_no_random(self):
36+
"""Test copying a list with a single node without random pointer."""
37+
node = ListNodeWithRandom(1)
38+
cloned_head = CopyListWithRandomPointer.copyRandomList(node)
39+
self.assertIsNotNone(cloned_head)
40+
self.assertEqual(cloned_head.val, 1)
41+
self.assertIsNone(cloned_head.next)
42+
self.assertIsNone(cloned_head.random)
43+
44+
def test_copy_random_list_single_node_with_random(self):
45+
"""Test copying a list with a single node with random pointer to itself."""
46+
node = ListNodeWithRandom(1)
47+
node.random = node
48+
cloned_head = CopyListWithRandomPointer.copyRandomList(node)
49+
self.assertIsNotNone(cloned_head)
50+
self.assertEqual(cloned_head.val, 1)
51+
self.assertIsNone(cloned_head.next)
52+
self.assertIsNotNone(cloned_head.random)
53+
self.assertEqual(cloned_head, cloned_head.random)
54+
55+
def test_copy_random_list_multiple_nodes_no_random(self):
56+
"""Test copying a list with multiple nodes and no random pointers."""
57+
node1 = ListNodeWithRandom(1)
58+
node2 = ListNodeWithRandom(2)
59+
node1.next = node2
60+
cloned_head = CopyListWithRandomPointer.copyRandomList(node1)
61+
self.assertIsNotNone(cloned_head)
62+
self.assertEqual(cloned_head.val, 1)
63+
self.assertIsNotNone(cloned_head.next)
64+
self.assertEqual(cloned_head.next.val, 2)
65+
self.assertIsNone(cloned_head.random)
66+
self.assertIsNone(cloned_head.next.random)
67+
68+
def test_copy_random_list_multiple_nodes_with_random(self):
69+
"""Test copying a list with multiple nodes and random pointers."""
70+
node1 = ListNodeWithRandom(1)
71+
node2 = ListNodeWithRandom(2)
72+
node3 = ListNodeWithRandom(3)
73+
node1.next = node2
74+
node2.next = node3
75+
node1.random = node3
76+
node2.random = node1
77+
node3.random = node2
78+
cloned_head = CopyListWithRandomPointer.copyRandomList(node1)
79+
self.assertIsNotNone(cloned_head)
80+
self.assertEqual(cloned_head.val, 1)
81+
self.assertIsNotNone(cloned_head.next)
82+
self.assertEqual(cloned_head.next.val, 2)
83+
self.assertIsNotNone(cloned_head.next.next)
84+
self.assertEqual(cloned_head.next.next.val, 3)
85+
self.assertIsNone(cloned_head.next.next.next)
86+
87+
# Verify random pointers
88+
self.assertEqual(cloned_head.random.val, 3)
89+
self.assertEqual(cloned_head.next.random.val, 1)
90+
self.assertEqual(cloned_head.next.next.random.val, 2)
91+
92+
93+
if __name__ == "__main__":
94+
unittest.main()

0 commit comments

Comments
 (0)