AiTechWorlds
AiTechWorlds
University learning companion
Algorithms · Binary Search Variations and Applications
A delivery service must process more stops as its business grows. Apply this topic to a small input first, record the intermediate state, establish why the result is correct, and then estimate what happens when the input becomes ten times larger.
Binary search repeatedly halves a sorted search space to find a target in logarithmic time, and the same halving logic extends far beyond looking up a value in a plain sorted array.
Steps of binary search over a sorted array. Image: AlwaysAngry · CC BY-SA 4.0. Source and attribution; unmodified.
You're on a game show. The host says: "There's a prize worth between $1 and $1,000. Guess the price. I'll tell you higher or lower after each guess."
What do you do? You don't start at $1 and count up. You guess $500. "Higher." You guess $750. "Lower." You guess $625. "Higher." You guess $687. "Lower."
Within ten guesses, you've pinpointed the exact price. You've just run binary search without even thinking about it.
This is the key insight: Binary search isn't just for finding values in arrays. It's a way of thinking about any problem where you can eliminate half the possibilities with a single test.
The template for any binary search problem is:
1. Define a search space [left, right]
2. Define a condition: does this value satisfy the requirement?
3. Narrow the space: if condition met → search left half (or right half)
4. Repeat until the space collapses to a single answerOnce you see this pattern, you'll find binary search hiding inside dozens of problem types.
Problem: In a sorted array with duplicates, find the first index where the target appears.
def find_first(arr, target):
left, right = 0, len(arr) - 1
result = -1 # Track best (leftmost) match found so far
while left <= right:
mid = left + (right - left) // 2
if arr[mid] == target:
result = mid # Record this match
right = mid - 1 # Keep searching LEFT for an earlier match
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return result
# --- Example ---
arr = [2, 4, 4, 4, 7, 9, 9, 11]
print(find_first(arr, 4)) # Output: 1 (first 4 is at index 1)
print(find_first(arr, 9)) # Output: 5 (first 9 is at index 5)Output:
1
5Problem: Find the last index where target appears.
def find_last(arr, target):
left, right = 0, len(arr) - 1
result = -1
while left <= right:
mid = left + (right - left) // 2
if arr[mid] == target:
result = mid # Record this match
left = mid + 1 # Keep searching RIGHT for a later match
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return result
# --- Example ---
arr = [2, 4, 4, 4, 7, 9, 9, 11]
print(find_last(arr, 4)) # Output: 3 (last 4 is at index 3)
print(find_last(arr, 9)) # Output: 6 (last 9 is at index 6)Output:
3
6Problem: Find where a value would be inserted to keep the array sorted.
Python's built in bisect module handles this perfectly:
import bisect
# bisect_left: find leftmost position to insert target
# bisect_right: find rightmost position to insert target
arr = [10, 20, 30, 40, 50]
print(bisect.bisect_left(arr, 30)) # Output: 2 (before existing 30)
print(bisect.bisect_right(arr, 30)) # Output: 3 (after existing 30)
print(bisect.bisect_left(arr, 25)) # Output: 2 (between 20 and 30)Output:
2
3
2import bisect
scores = [10, 20, 30, 40, 50, 60, 70, 80, 90]
grade_boundaries = [60, 70, 80, 90, 100]
grades = ['F', 'D', 'C', 'B', 'A']
def get_grade(score):
# bisect_left finds where score fits in grade_boundaries
# That index maps directly to the grades list
return grades[bisect.bisect_left(grade_boundaries, score)]
for score in [55, 65, 75, 85, 95]:
print(f"Score {score}: {get_grade(score)}")Output:
Score 55: F
Score 65: D
Score 75: C
Score 85: B
Score 95: AHow it works: bisect_left(grade_boundaries, 65) finds that 65 belongs at index 1 (after 60, before 70) which maps to grades[1] = 'D'. No if elif chains needed.
Problem: A sorted array has been rotated at some pivot. Example: [4, 5, 6, 7, 0, 1, 2] (rotated from [0, 1, 2, 4, 5, 6, 7]). Find the target.
Original: [0, 1, 2, 4, 5, 6, 7]
Rotated: [4, 5, 6, 7, 0, 1, 2]
^--- rotation pointdef search_rotated(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = left + (right - left) // 2
if arr[mid] == target:
return mid
# Determine which half is sorted
if arr[left] <= arr[mid]: # LEFT half is sorted
if arr[left] <= target < arr[mid]: # Target is in left half
right = mid - 1
else: # Target is in right half
left = mid + 1
else: # RIGHT half is sorted
if arr[mid] < target <= arr[right]: # Target is in right half
left = mid + 1
else: # Target is in left half
right = mid - 1
return -1
# --- Example ---
arr = [4, 5, 6, 7, 0, 1, 2]
print(search_rotated(arr, 0)) # Output: 4
print(search_rotated(arr, 3)) # Output: -1Output:
4
-1Problem: A peak element is one that is greater than its neighbors. Find any peak.
def find_peak(arr):
left, right = 0, len(arr) - 1
while left < right:
mid = left + (right - left) // 2
if arr[mid] > arr[mid + 1]: # Descending — peak is in LEFT half
right = mid # (mid itself could be the peak)
else: # Ascending — peak is in RIGHT half
left = mid + 1
return left # left == right, this is the peak index
# --- Example ---
arr = [1, 3, 20, 4, 1, 0]
peak_idx = find_peak(arr)
print(f"Peak is {arr[peak_idx]} at index {peak_idx}") # Output: Peak is 20 at index 2Output:
Peak is 20 at index 2This is the most powerful application. Instead of searching an array, you search the space of possible answers.
Pattern: "Find the minimum value of X such that condition(X) is true."
Example Problem: What is the minimum number of days needed to ship all packages if you can carry at most capacity weight per day?
def can_ship(weights, capacity, days):
"""Check if all packages can be shipped in `days` days with given capacity."""
current_load = 0
days_used = 1
for w in weights:
if current_load + w > capacity:
days_used += 1
current_load = 0
current_load += w
return days_used <= days
def min_ship_capacity(weights, days):
left = max(weights) # Minimum: must fit heaviest package
right = sum(weights) # Maximum: ship everything in one day
while left < right:
mid = left + (right - left) // 2
if can_ship(weights, mid, days):
right = mid # mid works — try smaller
else:
left = mid + 1 # mid too small — try larger
return left
# --- Example ---
weights = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(min_ship_capacity(weights, 5)) # Output: 15Output:
15The answer space is [10, 55]. We binary search over possible capacities, checking if each one allows shipping in 5 days.
def binary_search_template(search_space_start, search_space_end, condition):
"""
Find the minimum value in [start, end] where condition(value) is True.
Assumes: condition is False for small values, True for large values.
"""
left, right = search_space_start, search_space_end
while left < right:
mid = left + (right - left) // 2
if condition(mid):
right = mid # mid satisfies condition — try smaller
else:
left = mid + 1 # mid doesn't satisfy — go larger
return left # Smallest value satisfying condition| Variation | Key Modification | Use When |
|---|---|---|
| Standard search | Return on match | Find any occurrence |
| First occurrence | On match, save & go left | Find leftmost duplicate |
| Last occurrence | On match, save & go right | Find rightmost duplicate |
| Insertion point | bisect_left / bisect_right | Maintain sorted order |
| Rotated array | Check which half is sorted | Rotated sorted array |
| Peak finding | Compare mid vs mid+1 | Find local maximum |
| Answer space | Search over possible values | Optimization with monotonic condition |
Binary search on answer space problems are among the most highly rated interview questions at top tech companies. They test whether you can recognize the abstract structure of a problem rather than just apply memorized algorithms.
Whenever you see: "find minimum X such that..." or "what is the smallest/largest value that satisfies...", think binary search on the answer space.
Common interview problems in this category:
University learning companion
Algorithms · Binary Search Variations and Applications
Complete the steps without looking at the answer first; record evidence rather than only a final result.
These are primary or established learning references for this subject. Check the relevant chapter or specification for the exact topic and version.
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises