From b98816801b9937bceaa37b9e2d8509b07cd3cfa2 Mon Sep 17 00:00:00 2001 From: SoulSniper1212 Date: Sun, 9 Nov 2025 20:10:37 -0500 Subject: [PATCH 1/2] Fix binary search to return leftmost occurrence for duplicates Signed-off-by: SoulSniper1212 --- searches/binary_search.py | 49 ++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/searches/binary_search.py b/searches/binary_search.py index 2e66b672d5b4..4484119931e4 100644 --- a/searches/binary_search.py +++ b/searches/binary_search.py @@ -186,7 +186,9 @@ def binary_search(sorted_collection: list[int], item: int) -> int: :param sorted_collection: some ascending sorted collection with comparable items :param item: item value to search - :return: index of the found item or -1 if the item is not found + :return: index of the found item or -1 if the item is not found. + If there are multiple occurrences of the item, returns the index + of the leftmost occurrence. Examples: >>> binary_search([0, 5, 7, 10, 15], 0) @@ -197,22 +199,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, 4, 4, 4, 6, 7], 4) + 2 + >>> binary_search([0, 5, 7, 10, 10, 10], 10) + 3 """ if list(sorted_collection) != sorted(sorted_collection): raise ValueError("sorted_collection must be sorted in ascending order") left = 0 right = len(sorted_collection) - 1 + result = -1 while left <= right: midpoint = left + (right - left) // 2 current_item = sorted_collection[midpoint] if current_item == item: - return midpoint + result = midpoint # Found the item, but continue to find leftmost occurrence + right = midpoint - 1 # Look for more occurrences on the left elif item < current_item: right = midpoint - 1 else: left = midpoint + 1 - return -1 + return result def binary_search_std_lib(sorted_collection: list[int], item: int) -> int: @@ -254,7 +262,9 @@ def binary_search_by_recursion( :param sorted_collection: some ascending sorted collection with comparable items :param item: item value to search - :return: index of the found item or -1 if the item is not found + :return: index of the found item or -1 if the item is not found. + If there are multiple occurrences of the item, returns the index + of the leftmost occurrence. Examples: >>> binary_search_by_recursion([0, 5, 7, 10, 15], 0, 0, 4) @@ -265,22 +275,35 @@ 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, 4, 4, 4, 6, 7], 4, 0, 6) + 2 + >>> binary_search_by_recursion([0, 5, 7, 10, 10, 10], 10, 0, 5) + 3 """ 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: - return -1 + + # Helper function for the binary search + def _binary_search_recursive(left_idx: int, right_idx: int) -> int: + if right_idx < left_idx: + return -1 - midpoint = left + (right - left) // 2 + midpoint = left_idx + (right_idx - left_idx) // 2 + current_item = sorted_collection[midpoint] - if sorted_collection[midpoint] == item: - return midpoint - elif sorted_collection[midpoint] > item: - return binary_search_by_recursion(sorted_collection, item, left, midpoint - 1) - else: - return binary_search_by_recursion(sorted_collection, item, midpoint + 1, right) + if current_item == item: + # Found the item, now find the leftmost occurrence + # First, recursively find any occurrence to the left + leftmost = _binary_search_recursive(left_idx, midpoint - 1) + return leftmost if leftmost != -1 else midpoint + elif item < current_item: + return _binary_search_recursive(left_idx, midpoint - 1) + else: + return _binary_search_recursive(midpoint + 1, right_idx) + + return _binary_search_recursive(left, right) def exponential_search(sorted_collection: list[int], item: int) -> int: From 13ee9fbef6b517eb8198f7219d8bcfd0e7e570ed Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 01:10:59 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- searches/binary_search.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/searches/binary_search.py b/searches/binary_search.py index 4484119931e4..d2e04f496327 100644 --- a/searches/binary_search.py +++ b/searches/binary_search.py @@ -214,7 +214,9 @@ def binary_search(sorted_collection: list[int], item: int) -> int: midpoint = left + (right - left) // 2 current_item = sorted_collection[midpoint] if current_item == item: - result = midpoint # Found the item, but continue to find leftmost occurrence + result = ( + midpoint # Found the item, but continue to find leftmost occurrence + ) right = midpoint - 1 # Look for more occurrences on the left elif item < current_item: right = midpoint - 1 @@ -284,7 +286,7 @@ def binary_search_by_recursion( right = len(sorted_collection) - 1 if list(sorted_collection) != sorted(sorted_collection): raise ValueError("sorted_collection must be sorted in ascending order") - + # Helper function for the binary search def _binary_search_recursive(left_idx: int, right_idx: int) -> int: if right_idx < left_idx: @@ -302,7 +304,7 @@ def _binary_search_recursive(left_idx: int, right_idx: int) -> int: return _binary_search_recursive(left_idx, midpoint - 1) else: return _binary_search_recursive(midpoint + 1, right_idx) - + return _binary_search_recursive(left, right)