diff --git a/searches/simple_binary_search.py b/searches/simple_binary_search.py index 00e83ff9e4a3..895434d7473d 100644 --- a/searches/simple_binary_search.py +++ b/searches/simple_binary_search.py @@ -11,50 +11,61 @@ from __future__ import annotations -def binary_search(a_list: list[int], item: int) -> bool: +def binary_search(a_list: list[int], item: int) -> int: """ + Returns the leftmost index of `item` in `a_list` if found, + otherwise returns -1. + >>> test_list = [0, 1, 2, 8, 13, 17, 19, 32, 42] >>> binary_search(test_list, 3) - False + -1 >>> binary_search(test_list, 13) - True + 4 >>> binary_search([4, 4, 5, 6, 7], 4) - True + 0 >>> binary_search([4, 4, 5, 6, 7], -10) - False + -1 >>> binary_search([-18, 2], -18) - True + 0 >>> binary_search([5], 5) - True + 0 >>> binary_search(['a', 'c', 'd'], 'c') - True + 1 >>> binary_search(['a', 'c', 'd'], 'f') - False + -1 >>> binary_search([], 1) - False + -1 >>> binary_search([-.1, .1 , .8], .1) - True + 1 >>> binary_search(range(-5000, 5000, 10), 80) - True + 508 >>> binary_search(range(-5000, 5000, 10), 1255) - False + -1 >>> binary_search(range(0, 10000, 5), 2) - False + -1 """ - if len(a_list) == 0: - return False - midpoint = len(a_list) // 2 - if a_list[midpoint] == item: - return True - if item < a_list[midpoint]: - return binary_search(a_list[:midpoint], item) - else: - return binary_search(a_list[midpoint + 1 :], item) + low, high = 0, len(a_list) - 1 + result = -1 + + while low <= high: + mid = (low + high) // 2 + if a_list[mid] == item: + result = mid + high = mid - 1 # keep searching left for duplicates + elif item < a_list[mid]: + high = mid - 1 + else: + low = mid + 1 + + return result if __name__ == "__main__": user_input = input("Enter numbers separated by comma:\n").strip() sequence = [int(item.strip()) for item in user_input.split(",")] target = int(input("Enter the number to be found in the list:\n").strip()) - not_str = "" if binary_search(sequence, target) else "not " - print(f"{target} was {not_str}found in {sequence}") + index = binary_search(sequence, target) + if index != -1: + print(f"{target} found at index {index} in {sequence}") + else: + print(f"{target} was not found in {sequence}") diff --git a/test.patch b/test.patch new file mode 100644 index 000000000000..2d55a363ca84 Binary files /dev/null and b/test.patch differ diff --git a/test.sh b/test.sh new file mode 100644 index 000000000000..23bcf5475b8d --- /dev/null +++ b/test.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -uo pipefail +cd /app + +MODE="${1:-new}" + +case "$MODE" in + base) + pytest tests # run existing repo tests + ;; + new) + pytest tests/test_binary_search_duplicates.py + ;; + *) + echo "unknown mode: $MODE (expected base or new)" >&2 + exit 2 + ;; +esac \ No newline at end of file diff --git a/tests/test_binary_search_duplicates.py b/tests/test_binary_search_duplicates.py new file mode 100644 index 000000000000..19892acf2c32 --- /dev/null +++ b/tests/test_binary_search_duplicates.py @@ -0,0 +1,10 @@ +def test_binary_search_leftmost_duplicate(): + assert binary_search([1, 2, 2, 2, 3], 2) == 1 + + +def test_binary_search_all_duplicates(): + assert binary_search([1, 1, 1, 1], 1) == 0 + + +def test_binary_search_not_found(): + assert binary_search([1, 2, 3], 4) == -1