Skip to content

Commit 22986b0

Browse files
Add linked list and binary search problems with solutions
Implemented multiple linked list and binary search problem solutions including `add_two_numbers`, `reverse_linked_list`, `merge_two_sorted_lists`, and `search_in_rotated_sorted_array`. Each includes unittests and follows PEP 8 for maintainability and clarity.
1 parent 9d1da98 commit 22986b0

9 files changed

+324
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# https://neetcode.io/problems/find-minimum-in-rotated-sorted-array
2+
3+
from typing import List
4+
5+
import unittest
6+
7+
8+
def find_min(nums: List[int]) -> int:
9+
n = len(nums)
10+
11+
left = 0
12+
right = n - 1
13+
14+
while left < right:
15+
mid = (right + left) // 2
16+
17+
if nums[mid] > nums[right]:
18+
left = mid + 1
19+
else:
20+
right = mid
21+
22+
return nums[left]
23+
24+
25+
class Test(unittest.TestCase):
26+
def test_find_min(self):
27+
self.assertEqual(find_min([3, 4, 5, 1, 2]), 1)
28+
self.assertEqual(find_min([4, 5, 6, 7, 0, 1, 2]), 0)
29+
self.assertEqual(find_min([11, 13, 15, 17]), 11)

Binary Search/median_of_two_sorted_arrays.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def find_median_sorted_arrays(nums1: List[int], nums2: List[int]) -> float:
4747
left = i + 1
4848

4949

50-
class TestFindMedianSortedArrays(unittest.TestCase):
50+
class Test(unittest.TestCase):
5151
def test_basic_case(self):
5252
nums1 = [1, 3]
5353
nums2 = [2]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# https://neetcode.io/problems/find-target-in-rotated-sorted-array
2+
3+
from typing import List
4+
5+
import unittest
6+
7+
8+
def search(nums: List[int], target: int) -> int:
9+
n = len(nums)
10+
11+
if n == 0:
12+
return -1
13+
14+
left = 0
15+
right = n - 1
16+
17+
while left <= right:
18+
mid = (right + left) // 2
19+
20+
if nums[mid] == target:
21+
return mid
22+
23+
if nums[mid] >= nums[left]:
24+
if nums[left] <= target < nums[mid]:
25+
right = mid - 1
26+
else:
27+
left = mid + 1
28+
else:
29+
if nums[mid] < target <= nums[right]:
30+
left = mid + 1
31+
else:
32+
right = mid - 1
33+
34+
return -1
35+
36+
37+
class Test(unittest.TestCase):
38+
def test_search(self):
39+
self.assertEqual(search([4, 5, 6, 7, 0, 1, 2], 0), 4)
40+
self.assertEqual(search([4, 5, 6, 7, 0, 1, 2], 3), -1)
41+
self.assertEqual(search([1], 0), -1)
42+
self.assertEqual(search([1], 1), 0)
43+
self.assertEqual(search([1, 3], 3), 1)
44+
self.assertEqual(search([3, 1], 3), 0)
45+
self.assertEqual(search([3, 1], 1), 1)
46+
self.assertEqual(search([3, 1], 0), -1)

Linked Lists/__init__.py

Whitespace-only changes.

Linked Lists/add_two_numbers.py

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# https://neetcode.io/problems/add-two-numbers
2+
3+
from typing import Optional
4+
5+
import unittest
6+
7+
# We can use `divmod` to get the quotient and the remainder of the division
8+
# see https://docs.python.org/3/library/functions.html#divmod
9+
# Doing it by hand:
10+
# new_digit = a + b + carry
11+
# carry = new_digit // 10
12+
# new_digit %= 10
13+
14+
15+
class ListNode:
16+
def __init__(self, val=0, next=None):
17+
self.val = val
18+
self.next = next
19+
20+
21+
def add_two_numbers(
22+
l1: Optional[ListNode], l2: Optional[ListNode]
23+
) -> Optional[ListNode]:
24+
sentinel = ListNode()
25+
current = sentinel
26+
27+
carry = 0
28+
29+
while l1 or l2 or carry:
30+
a = l1.val if l1 else 0
31+
b = l2.val if l2 else 0
32+
33+
carry, new_digit = divmod(a + b + carry, 10)
34+
35+
current.next = ListNode(new_digit)
36+
37+
current = current.next
38+
39+
l1 = l1.next if l1 else None
40+
l2 = l2.next if l2 else None
41+
42+
return sentinel.next
43+
44+
45+
class Test(unittest.TestCase):
46+
def test_add_two_numbers(self):
47+
l1 = ListNode(2, ListNode(4, ListNode(3)))
48+
l2 = ListNode(5, ListNode(6, ListNode(4)))
49+
self.assertEqual(add_two_numbers(l1, l2).val, 7)
50+
self.assertEqual(add_two_numbers(l1, l2).next.val, 0)
51+
self.assertEqual(add_two_numbers(l1, l2).next.next.val, 8)

Linked Lists/linked_list_cycle.py

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# https://neetcode.io/problems/linked-list-cycle-detection
2+
3+
from typing import Optional
4+
5+
import unittest
6+
7+
8+
class ListNode:
9+
def __init__(self, val=0, next=None):
10+
self.val = val
11+
self.next = next
12+
13+
14+
def has_cycle(head: Optional[ListNode]) -> bool:
15+
slow = head
16+
fast = head.next
17+
18+
while fast and fast.next:
19+
slow = slow.next
20+
fast = fast.next.next
21+
22+
if slow == fast:
23+
return True
24+
25+
return False
26+
27+
28+
class Test(unittest.TestCase):
29+
def test_hasCycle(self):
30+
head = ListNode(3, ListNode(2, ListNode(0, ListNode(-4))))
31+
head.next.next.next.next = head.next
32+
33+
self.assertTrue(has_cycle(head))
34+
35+
head = ListNode(1, ListNode(2))
36+
head.next.next = head
37+
38+
self.assertTrue(has_cycle(head))
39+
40+
head = ListNode(1)
41+
42+
self.assertFalse(has_cycle(head))
43+
44+
head = ListNode(1, ListNode(2, ListNode(3)))
45+
46+
self.assertFalse(has_cycle(head))
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# https://neetcode.io/problems/merge-two-sorted-linked-lists
2+
3+
from typing import Optional
4+
5+
import unittest
6+
7+
8+
class ListNode:
9+
def __init__(self, val=0, next=None):
10+
self.val = val
11+
self.next = next
12+
13+
14+
def merge_two_lists(
15+
list1: Optional[ListNode], list2: Optional[ListNode]
16+
) -> Optional[ListNode]:
17+
sentinel = ListNode()
18+
current = sentinel
19+
20+
while list1 and list2:
21+
if list1.val < list2.val:
22+
current.next = list1
23+
list1 = list1.next
24+
else:
25+
current.next = list2
26+
list2 = list2.next
27+
28+
current = current.next
29+
30+
# Attach remaining portion of list1 or list2
31+
current.next = list1 or list2
32+
33+
return sentinel.next
34+
35+
36+
class Test(unittest.TestCase):
37+
def test_mergeTwoLists(self):
38+
list1 = ListNode(1, ListNode(2, ListNode(4)))
39+
list2 = ListNode(1, ListNode(3, ListNode(4)))
40+
41+
result = merge_two_lists(None, list1, list2)
42+
43+
self.assertEqual(result.val, 1)
44+
self.assertEqual(result.next.val, 1)
45+
self.assertEqual(result.next.next.val, 2)
46+
self.assertEqual(result.next.next.next.val, 3)
47+
self.assertEqual(result.next.next.next.next.val, 4)
48+
self.assertEqual(result.next.next.next.next.next.val, 4)

Linked Lists/reorder_list.py

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# https://neetcode.io/problems/reorder-linked-list
2+
3+
from typing import Optional
4+
5+
import unittest
6+
7+
8+
class ListNode:
9+
def __init__(self, val=0, next=None):
10+
self.val = val
11+
self.next = next
12+
13+
14+
def reorder_list(head: Optional[ListNode]) -> None:
15+
# Find middle of linked list
16+
17+
slow = head
18+
fast = head.next
19+
20+
while fast and fast.next:
21+
slow = slow.next
22+
fast = fast.next.next
23+
24+
# Slow now points to the middle of the list
25+
second = slow.next
26+
previous = slow.next = None # Detach the second half
27+
28+
# Reverse
29+
30+
while second:
31+
nxt = second.next
32+
33+
second.next = previous
34+
previous = second
35+
36+
second = nxt
37+
38+
# Merge
39+
40+
first = head
41+
second = previous
42+
43+
while second:
44+
nxt1, nxt2 = first.next, second.next
45+
46+
first.next = second
47+
second.next = nxt1
48+
49+
first, second = nxt1, nxt2
50+
51+
52+
class Test(unittest.TestCase):
53+
def test_reorderList(self):
54+
head = ListNode(1)
55+
head.next = ListNode(2)
56+
head.next.next = ListNode(3)
57+
head.next.next.next = ListNode(4)
58+
59+
reorder_list(head)
60+
61+
self.assertEqual(head.val, 1)
62+
self.assertEqual(head.next.val, 4)
63+
self.assertEqual(head.next.next.val, 2)
64+
self.assertEqual(head.next.next.next.val, 3)

Linked Lists/reverse_linked_list.py

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# https://neetcode.io/problems/reverse-a-linked-list
2+
3+
from typing import Optional
4+
5+
import unittest
6+
7+
8+
class ListNode:
9+
def __init__(self, val=0, next=None):
10+
self.val = val
11+
self.next = next
12+
13+
14+
def reverse_linked_list(head: Optional[ListNode]) -> Optional[ListNode]:
15+
prev = None
16+
current = head
17+
18+
while current:
19+
next_node = current.next
20+
21+
current.next = prev
22+
23+
prev = current
24+
current = next_node
25+
26+
return prev
27+
28+
29+
class Test(unittest.TestCase):
30+
def test_reverse_linked_list(self):
31+
head = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5)))))
32+
reversed_head = reverse_linked_list(head)
33+
34+
self.assertEqual(reversed_head.val, 5)
35+
self.assertEqual(reversed_head.next.val, 4)
36+
self.assertEqual(reversed_head.next.next.val, 3)
37+
self.assertEqual(reversed_head.next.next.next.val, 2)
38+
self.assertEqual(reversed_head.next.next.next.next.val, 1)
39+
self.assertIsNone(reversed_head.next.next.next.next.next)

0 commit comments

Comments
 (0)