Skip to content

Commit c11ea5b

Browse files
committed
feat(data-structures, linked lists): sum two linked lists
1 parent 60f4cde commit c11ea5b

File tree

2 files changed

+114
-2
lines changed

2 files changed

+114
-2
lines changed

datastructures/linked_lists/linked_list_utils.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,60 @@ def remove_nth_from_end(head: Optional[Node], n: int) -> Optional[Node]:
173173

174174
# Return the modified head node of the linked list with the node removed
175175
return head
176+
177+
178+
def sum_of_linked_lists(
179+
head_one: Optional[Node], head_two: Optional[Node]
180+
) -> Optional[Node]:
181+
"""
182+
Sums two linked lists together to create a new linked list. The two heads of the two linked lists provided represent
183+
two non-negative integers. The digits are in reverse order and each of their nodes contains a single digit. This
184+
adds the two numbers and returns the sum as a linked list. This assumes that the two numbers do not contain any
185+
leading zero, except the number 0 itself.
186+
187+
Example:
188+
Input: l1 = [2,4,3], l2 = [5,6,4]
189+
Output: [7,0,8]
190+
Explanation: 342 + 465 = 807.
191+
192+
Complexity:
193+
Time: O(max(m, n)). Assume that m and n represent the lengths of the first and the second linked lists respectively,
194+
the algorithm iterates at most max(m, n) times
195+
196+
Space: O(1). The length of the new linked list is at most max(m, n) + 1
197+
198+
Args:
199+
head_one(Node): head node of the first linked list
200+
head_two(Node): head node of the second linked list
201+
Returns:
202+
Node: head node of newly crewted linked list
203+
"""
204+
if not head_one and head_two:
205+
return head_two
206+
if not head_two and head_one:
207+
return head_one
208+
if not head_one and not head_two:
209+
return None
210+
211+
dummy_head = Node(0)
212+
carry = 0
213+
pointer_one, pointer_two = head_one, head_two
214+
current = dummy_head
215+
216+
while pointer_one or pointer_two:
217+
x = pointer_one.data if pointer_one else 0
218+
y = pointer_two.data if pointer_two else 0
219+
current_sum = carry + x + y
220+
carry = current_sum // 10
221+
current.next = Node(current_sum % 10)
222+
current = current.next
223+
224+
if pointer_one:
225+
pointer_one = pointer_one.next
226+
if pointer_two:
227+
pointer_two = pointer_two.next
228+
229+
if carry > 0:
230+
current.next = Node(carry)
231+
232+
return dummy_head.next

datastructures/linked_lists/test_linked_list_utils.py

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
from typing import List
33
from parameterized import parameterized
44
from datastructures.linked_lists.singly_linked_list.node import SingleNode
5-
from datastructures.linked_lists.linked_list_utils import remove_nth_from_end
5+
from datastructures.linked_lists.linked_list_utils import (
6+
remove_nth_from_end,
7+
sum_of_linked_lists,
8+
)
69

710
REMOVE_NTH_NODE_FROM_END_TEST_CASES = [
811
([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 4, [0, 1, 2, 3, 4, 5, 7, 8, 9]),
9-
([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 10, [1, 2, 3, 4, 5, 6, 7, 8, 9])
12+
([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 10, [1, 2, 3, 4, 5, 6, 7, 8, 9]),
1013
]
1114

1215

@@ -35,5 +38,57 @@ def test_remove_nth_node_from_end(
3538
self.assertListEqual(expected, actual_data)
3639

3740

41+
SUM_LINKED_LISTS_TEST_CASES = [
42+
([2, 4, 3], [5, 6, 4], [7, 0, 8]),
43+
([0], [0], [0]),
44+
([9, 9, 9, 9, 9, 9, 9], [9, 9, 9, 9], [8, 9, 9, 9, 0, 0, 0, 1]),
45+
]
46+
47+
48+
class SumLinkedListsTestCase(unittest.TestCase):
49+
@staticmethod
50+
def construct_linked_list(data: List[int]) -> SingleNode:
51+
head = SingleNode(data[0])
52+
current = head
53+
for d in data[1:]:
54+
current.next = SingleNode(d)
55+
current = current.next
56+
return head
57+
58+
def assert_data(self, actual: SingleNode, expected: List[int]):
59+
actual_current_head = actual
60+
actual_data = []
61+
while actual_current_head:
62+
actual_data.append(actual_current_head.data)
63+
actual_current_head = actual_current_head.next
64+
65+
self.assertListEqual(expected, actual_data)
66+
67+
@parameterized.expand(SUM_LINKED_LISTS_TEST_CASES)
68+
def test_sum_linked_lists(
69+
self, data_one: List[int], data_two: List[int], expected: List[int]
70+
):
71+
if not data_one and not data_two:
72+
actual = sum_of_linked_lists(head_one=None, head_two=None)
73+
self.assertIsNone(actual)
74+
75+
if not data_one and data_two:
76+
head = self.construct_linked_list(data_two)
77+
actual = sum_of_linked_lists(head_one=None, head_two=head)
78+
self.assertEqual(expected, actual)
79+
80+
if data_one and not data_two:
81+
head = self.construct_linked_list(data_one)
82+
actual = sum_of_linked_lists(head_one=None, head_two=head)
83+
self.assertEqual(expected, actual)
84+
85+
head_one = self.construct_linked_list(data_one)
86+
head_two = self.construct_linked_list(data_two)
87+
88+
actual = sum_of_linked_lists(head_one=head_one, head_two=head_two)
89+
self.assertIsNotNone(actual)
90+
self.assert_data(actual, expected)
91+
92+
3893
if __name__ == "__main__":
3994
unittest.main()

0 commit comments

Comments
 (0)