diff --git a/searches/exponential_search.py b/searches/exponential_search.py index eddf97e5f0b4..9fb6e7b0c712 100644 --- a/searches/exponential_search.py +++ b/searches/exponential_search.py @@ -47,21 +47,29 @@ def binary_search_by_recursion( >>> binary_search_by_recursion([0, 5, 7, 10, 15], 16) -1 """ - if right is None: - 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 + if right is None: + right = len(sorted_collection) - 1 - midpoint = left + (right - left) // 2 + # Recursive core: ``left`` and ``right`` are always concrete indices here, so the + # window can only shrink. Keeping the recursion flat (no ``None`` sentinel, no + # re-expansion) is what prevents the runaway recursion when the item sits below + # ``sorted_collection[0]`` and ``right`` legitimately drops below ``left``. + def _search(left: int, right: int) -> int: + if right < left: + return -1 - 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) + midpoint = left + (right - left) // 2 + + if sorted_collection[midpoint] == item: + return midpoint + elif sorted_collection[midpoint] > item: + return _search(left, midpoint - 1) + else: + return _search(midpoint + 1, right) + + return _search(left, right) def exponential_search(sorted_collection: list[int], item: int) -> int: