Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion matrix/binary_search_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,20 @@ def binary_search(array: list, lower_bound: int, upper_bound: int, value: int) -
0
>>> binary_search(matrix, 0, len(matrix) - 1, 23)
-1
>>> matrix_dup = [1, 4, 4, 4, 7, 11, 15]
>>> binary_search(matrix_dup, 0, len(matrix_dup) - 1, 4)
1
>>> binary_search(matrix_dup, 0, len(matrix_dup) - 1, 7)
4
>>> binary_search(matrix_dup, 0, len(matrix_dup) - 1, 0)
-1
"""

r = int((lower_bound + upper_bound) // 2)
r = (lower_bound + upper_bound) // 2
if array[r] == value:
# Move left to find the first occurrence of duplicates
while r > 0 and array[r - 1] == value:
r -= 1
return r
if lower_bound >= upper_bound:
return -1
Expand Down
39 changes: 25 additions & 14 deletions other/number_container_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ def binary_search_delete(self, array: list | str | range, item: int) -> list[int
Traceback (most recent call last):
...
TypeError: binary_search_delete() only accepts either a list, range or str
>>> NumberContainer().binary_search_delete([1,2,2,3], 2)
[1, 2, 3]
>>> NumberContainer().binary_search_delete([0,0,1,1,1], 1)
[0, 0, 1, 1]
"""
if isinstance(array, (range, str)):
array = list(array)
Expand All @@ -60,19 +64,27 @@ def binary_search_delete(self, array: list | str | range, item: int) -> list[int

low = 0
high = len(array) - 1
result_index = -1

# Find the first occurrence of `item`
while low <= high:
mid = (low + high) // 2
if array[mid] == item:
array.pop(mid)
return array
elif array[mid] < item:
if array[mid] < item:
low = mid + 1
elif array[mid] > item:
high = mid - 1
else:
# Found the item, move left to find the first occurrence
result_index = mid
high = mid - 1
raise ValueError(
"Either the item is not in the array or the array was unsorted"
)

if result_index == -1:
raise ValueError(
"Either the item is not in the array or the array was unsorted"
)

array.pop(result_index)
return array

def binary_search_insert(self, array: list | str | range, index: int) -> list[int]:
"""
Expand All @@ -95,6 +107,10 @@ def binary_search_insert(self, array: list | str | range, index: int) -> list[in
Traceback (most recent call last):
...
TypeError: binary_search_insert() only accepts either a list, range or str
>>> NumberContainer().binary_search_insert([1,2,2,3], 2)
[1, 2, 2, 2, 3]
>>> NumberContainer().binary_search_insert([0,0,1,1], 1)
[0, 0, 1, 1, 1]
"""
if isinstance(array, (range, str)):
array = list(array)
Expand All @@ -106,19 +122,14 @@ def binary_search_insert(self, array: list | str | range, index: int) -> list[in
low = 0
high = len(array) - 1

# Find the correct insertion position
while low <= high:
mid = (low + high) // 2
if array[mid] == index:
# If the item already exists in the array,
# insert it after the existing item
array.insert(mid + 1, index)
return array
elif array[mid] < index:
if array[mid] < index:
low = mid + 1
else:
high = mid - 1

# If the item doesn't exist in the array, insert it at the appropriate position
array.insert(low, index)
return array

Expand Down
37 changes: 28 additions & 9 deletions searches/binary_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,21 +197,28 @@ def binary_search(sorted_collection: list[int], item: int) -> int:
1
>>> binary_search([0, 5, 7, 10, 15], 6)
-1
>>> binary_search([1, 2, 2, 2, 3], 2)
2
>>> binary_search([4, 4, 4, 4], 4)
1
"""
if list(sorted_collection) != sorted(sorted_collection):
raise ValueError("sorted_collection must be sorted in ascending order")

left = 0
right = len(sorted_collection) - 1

while left <= right:
midpoint = left + (right - left) // 2
current_item = sorted_collection[midpoint]

if current_item == item:
return midpoint
elif item < current_item:
right = midpoint - 1
else:
return midpoint # correct handling even with duplicates
elif current_item < item:
left = midpoint + 1
else:
right = midpoint - 1

return -1


Expand All @@ -234,12 +241,17 @@ def binary_search_std_lib(sorted_collection: list[int], item: int) -> int:
1
>>> binary_search_std_lib([0, 5, 7, 10, 15], 6)
-1
>>> binary_search_std_lib([1, 2, 2, 2, 3], 2)
1
>>> binary_search_std_lib([4, 4, 4, 4], 4)
0
"""
if list(sorted_collection) != sorted(sorted_collection):
raise ValueError("sorted_collection must be sorted in ascending order")

index = bisect.bisect_left(sorted_collection, item)
if index != len(sorted_collection) and sorted_collection[index] == item:
return index
return index # bisect_left handles duplicates correctly
return -1


Expand All @@ -265,19 +277,26 @@ def binary_search_by_recursion(
1
>>> binary_search_by_recursion([0, 5, 7, 10, 15], 6, 0, 4)
-1
>>> binary_search_by_recursion([1, 2, 2, 2, 3], 2, 0, 4)
2
>>> binary_search_by_recursion([4, 4, 4, 4], 4, 0, 3)
1
"""
if right < 0:
right = len(sorted_collection) - 1

if list(sorted_collection) != sorted(sorted_collection):
raise ValueError("sorted_collection must be sorted in ascending order")
if right < left:

if left > right:
return -1

midpoint = left + (right - left) // 2
mid_value = sorted_collection[midpoint]

if sorted_collection[midpoint] == item:
return midpoint
elif sorted_collection[midpoint] > item:
if mid_value == item:
return midpoint # valid index even with duplicates
elif mid_value > item:
return binary_search_by_recursion(sorted_collection, item, left, midpoint - 1)
else:
return binary_search_by_recursion(sorted_collection, item, midpoint + 1, right)
Expand Down
19 changes: 15 additions & 4 deletions searches/exponential_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ def binary_search_by_recursion(
1
>>> binary_search_by_recursion([0, 5, 7, 10, 15], 6, 0, 4)
-1
>>> binary_search_by_recursion([1, 2, 2, 2, 3], 2, 0, 4)
1
>>> binary_search_by_recursion([2, 2, 2, 2], 2, 0, 3)
0
"""
if right < 0:
right = len(sorted_collection) - 1
Expand All @@ -48,10 +52,17 @@ def binary_search_by_recursion(
return -1

midpoint = left + (right - left) // 2

if sorted_collection[midpoint] == item:
return midpoint
elif sorted_collection[midpoint] > item:
mid_value = sorted_collection[midpoint]

if mid_value == item:
# check if this is the first occurrence
if midpoint == 0 or sorted_collection[midpoint - 1] < item:
return midpoint
else:
return binary_search_by_recursion(
sorted_collection, item, left, midpoint - 1
)
elif mid_value > item:
return binary_search_by_recursion(sorted_collection, item, left, midpoint - 1)
else:
return binary_search_by_recursion(sorted_collection, item, midpoint + 1, right)
Expand Down
8 changes: 8 additions & 0 deletions searches/simple_binary_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ def binary_search(a_list: list[int], item: int) -> bool:
False
>>> binary_search(range(0, 10000, 5), 2)
False
>>> binary_search([1, 1, 1, 2, 2, 3], 1)
True
>>> binary_search([1, 1, 1, 2, 2, 3], 2)
True
>>> binary_search([1, 1, 1, 2, 2, 3], 3)
True
>>> binary_search([1, 1, 1, 2, 2, 3], 4)
False
"""
if len(a_list) == 0:
return False
Expand Down
12 changes: 9 additions & 3 deletions sorts/tim_sort.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
def binary_search(lst, item, start, end):
if start == end:
return start if lst[start] > item else start + 1
"""
Binary search that returns the index of the first occurrence of `item` if present,
or the correct insertion index if not present, even with duplicates.
"""
if start > end:
return start

mid = (start + end) // 2

if lst[mid] < item:
return binary_search(lst, item, mid + 1, end)
elif lst[mid] > item:
return binary_search(lst, item, start, mid - 1)
else:
elif mid == start or lst[mid - 1] != item:
# Move left to find the first occurrence
return mid
else:
return binary_search(lst, item, start, mid - 1)


def insertion_sort(lst):
Expand Down