Skip to content
Merged
Changes from 1 commit
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
65 changes: 65 additions & 0 deletions searches/binary_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,71 @@ def binary_search_std_lib(sorted_collection: list[int], item: int) -> int:
return -1


def binary_search_with_duplicates(sorted_collection: list[int], item: int) -> list[int]:
"""Pure implementation of a binary search algorithm in Python that supports
duplicates.

Resources used:
https://stackoverflow.com/questions/13197552/using-binary-search-with-sorted-array-with-duplicates
Comment thread
shuhao-alan-fan marked this conversation as resolved.

The collection must be sorted in ascending order; otherwise the result will be
unpredictable. If the target appears multiple times, this function returns a
list of **all** indexes where the target occurs. If the target is not found,
Comment thread
shuhao-alan-fan marked this conversation as resolved.
Outdated
it returns an empty list.
Comment thread
poyea marked this conversation as resolved.
Outdated

:param sorted_collection: some ascending sorted collection with comparable items
:param item: item value to search for
:return: a list of indexes where the item is found (empty list if not found)

Examples:
>>> binary_search_with_duplicates([0, 5, 7, 10, 15], 0)
[0]
>>> binary_search_with_duplicates([0, 5, 7, 10, 15], 15)
[4]
>>> binary_search_with_duplicates([1, 2, 2, 2, 3], 2)
[1, 2, 3]
>>> binary_search_with_duplicates([1, 2, 2, 2, 3], 4)
[]
Comment thread
poyea marked this conversation as resolved.
"""
Comment thread
shuhao-alan-fan marked this conversation as resolved.
if list(sorted_collection) != sorted(sorted_collection):
raise ValueError("sorted_collection must be sorted in ascending order")

"""find lower bounds"""
Comment thread
shuhao-alan-fan marked this conversation as resolved.
Outdated

def lower_bound(sorted_collection: list[int], item: int) -> int:
left = 0
right = len(sorted_collection)
while left < right:
midpoint = left + (right - left) // 2
current_item = sorted_collection[midpoint]
if current_item < item:
left = midpoint + 1
else:
right = midpoint
return left
Comment thread
shuhao-alan-fan marked this conversation as resolved.
Comment thread
shuhao-alan-fan marked this conversation as resolved.

"""find upper bounds"""
Comment thread
shuhao-alan-fan marked this conversation as resolved.
Outdated

def upper_bound(sorted_collection: list[int], item: int) -> int:
left = 0
right = len(sorted_collection)
while left < right:
midpoint = left + (right - left) // 2
current_item = sorted_collection[midpoint]
if current_item <= item:
left = midpoint + 1
else:
right = midpoint
return left
Comment thread
shuhao-alan-fan marked this conversation as resolved.
Comment thread
shuhao-alan-fan marked this conversation as resolved.

left = lower_bound(sorted_collection, item)
right = upper_bound(sorted_collection, item)
Comment thread
shuhao-alan-fan marked this conversation as resolved.

Comment thread
poyea marked this conversation as resolved.
if left == len(sorted_collection) or sorted_collection[left] != item:
return []
return list(range(left, right))


def binary_search_by_recursion(
sorted_collection: list[int], item: int, left: int = 0, right: int = -1
) -> int:
Expand Down