@@ -185,7 +185,9 @@ def binary_search(sorted_collection: list[int], item: int) -> int:
185185
186186 :param sorted_collection: some ascending sorted collection with comparable items
187187 :param item: item value to search
188- :return: index of the found item or -1 if the item is not found
188+ :return: index of the found item or -1 if the item is not found.
189+ If there are multiple occurrences of the item, returns the index
190+ of the leftmost occurrence.
189191
190192 Examples:
191193 >>> binary_search([0, 5, 7, 10, 15], 0)
@@ -196,22 +198,30 @@ def binary_search(sorted_collection: list[int], item: int) -> int:
196198 1
197199 >>> binary_search([0, 5, 7, 10, 15], 6)
198200 -1
201+ >>> binary_search([1, 2, 4, 4, 4, 6, 7], 4)
202+ 2
203+ >>> binary_search([0, 5, 7, 10, 10, 10], 10)
204+ 3
199205 """
200206 if any (a > b for a , b in pairwise (sorted_collection )):
201207 raise ValueError ("sorted_collection must be sorted in ascending order" )
202208 left = 0
203209 right = len (sorted_collection ) - 1
210+ result = - 1
204211
205212 while left <= right :
206213 midpoint = left + (right - left ) // 2
207214 current_item = sorted_collection [midpoint ]
208215 if current_item == item :
209- return midpoint
216+ result = (
217+ midpoint # Found the item, but continue to find leftmost occurrence
218+ )
219+ right = midpoint - 1 # Look for more occurrences on the left
210220 elif item < current_item :
211221 right = midpoint - 1
212222 else :
213223 left = midpoint + 1
214- return - 1
224+ return result
215225
216226
217227def binary_search_std_lib (sorted_collection : list [int ], item : int ) -> int :
@@ -328,7 +338,9 @@ def binary_search_by_recursion(
328338
329339 :param sorted_collection: some ascending sorted collection with comparable items
330340 :param item: item value to search
331- :return: index of the found item or -1 if the item is not found
341+ :return: index of the found item or -1 if the item is not found.
342+ If there are multiple occurrences of the item, returns the index
343+ of the leftmost occurrence.
332344
333345 Examples:
334346 >>> binary_search_by_recursion([0, 5, 7, 10, 15], 0, 0, 4)
@@ -339,22 +351,35 @@ def binary_search_by_recursion(
339351 1
340352 >>> binary_search_by_recursion([0, 5, 7, 10, 15], 6, 0, 4)
341353 -1
354+ >>> binary_search_by_recursion([1, 2, 4, 4, 4, 6, 7], 4, 0, 6)
355+ 2
356+ >>> binary_search_by_recursion([0, 5, 7, 10, 10, 10], 10, 0, 5)
357+ 3
342358 """
343359 if right < 0 :
344360 right = len (sorted_collection ) - 1
345361 if list (sorted_collection ) != sorted (sorted_collection ):
346362 raise ValueError ("sorted_collection must be sorted in ascending order" )
347- if right < left :
348- return - 1
349363
350- midpoint = left + (right - left ) // 2
364+ # Helper function for the binary search
365+ def _binary_search_recursive (left_idx : int , right_idx : int ) -> int :
366+ if right_idx < left_idx :
367+ return - 1
351368
352- if sorted_collection [midpoint ] == item :
353- return midpoint
354- elif sorted_collection [midpoint ] > item :
355- return binary_search_by_recursion (sorted_collection , item , left , midpoint - 1 )
356- else :
357- return binary_search_by_recursion (sorted_collection , item , midpoint + 1 , right )
369+ midpoint = left_idx + (right_idx - left_idx ) // 2
370+ current_item = sorted_collection [midpoint ]
371+
372+ if current_item == item :
373+ # Found the item, now find the leftmost occurrence
374+ # First, recursively find any occurrence to the left
375+ leftmost = _binary_search_recursive (left_idx , midpoint - 1 )
376+ return leftmost if leftmost != - 1 else midpoint
377+ elif item < current_item :
378+ return _binary_search_recursive (left_idx , midpoint - 1 )
379+ else :
380+ return _binary_search_recursive (midpoint + 1 , right_idx )
381+
382+ return _binary_search_recursive (left , right )
358383
359384
360385def exponential_search (sorted_collection : list [int ], item : int ) -> int :
0 commit comments