Binary Search
Classic Search • Rotated Array • Answer Space • Lower/Upper Bound
Section 1 — What Is Binary Search?
Binary search finds a target in a sorted (or monotone) space by repeatedly halving the search interval. Each comparison eliminates half the remaining candidates, giving O(log n) time — far superior to O(n) linear search for large inputs.
- At every step, the answer (if it exists) lies within
[lo, hi]. - We compute
mid = lo + (hi - lo) / 2(avoids integer overflow vs(lo+hi)/2). - We then shrink the window: move
loup orhidown based on the comparison atmid. - The loop terminates when
lo > hi(classic) orlo == hi(boundary search). - Critical: every iteration MUST reduce the window size. If
loorhinever moves, the loop runs forever.
1.1 — The Three Binary Search Templates
Most binary search bugs come from wrong loop condition or wrong boundary update. The following three templates cover 99% of interview problems.
// ── TEMPLATE 1: Classic exact search ────────────────────────
// Use when: searching for an exact value in a sorted array.
// Loop exits when lo > hi (element not found).
int bsClassic(vector<int>& a, int target) {
int lo = 0, hi = (int)a.size() - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] == target) return mid; // found
else if (a[mid] < target) lo = mid + 1; // target in right half
else hi = mid - 1; // target in left half
}
return -1; // not found
}
// ── TEMPLATE 2: Lower bound ──────────────────────────────────
// Use when: find first index where a[i] >= target.
// Loop exits when lo == hi == insertion point.
int lowerBound(vector<int>& a, int target) {
int lo = 0, hi = (int)a.size(); // hi = n (one past end) is valid
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] < target) lo = mid + 1; // mid is too small, exclude it
else hi = mid; // mid could be the answer, keep it
}
return lo; // first index with a[lo] >= target
}
// ── TEMPLATE 3: Upper bound ──────────────────────────────────
// Use when: find first index where a[i] > target.
int upperBound(vector<int>& a, int target) {
int lo = 0, hi = (int)a.size();
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] <= target) lo = mid + 1; // mid is not strictly greater
else hi = mid;
}
return lo; // first index with a[lo] > target
}
// C++ equivalents: lower_bound(a.begin(),a.end(),t) and upper_bound(...)1.2 — Template Comparison
| Template | Loop Condition | hi initialised to | lo/hi Update | Returns |
|---|---|---|---|---|
| Classic exact | lo <= hi | n - 1 | lo=mid+1 or hi=mid-1 | Index or -1 |
| Lower bound | lo < hi | n | lo=mid+1 or hi=mid | First idx >= target |
| Upper bound | lo < hi | n | lo=mid+1 or hi=mid | First idx > target |
| Answer space | lo < hi or <= | problem max | depends on feasibility | Optimal value |
Section 2 — Visual Diagrams: Binary Search in Action
Diagram 1 — Classic Binary Search
Classic Binary Search: Target = 7
Array: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] target = 7
Index: 0 1 2 3 4 5 6 7 8 9
Iteration 1: lo=0, hi=9, mid=4, a[mid]=9
9 > 7 => search left half. hi = mid-1 = 3.
[1, 3, 5, 7] [9, 11, 13, 15, 17, 19]
lo=0 hi=3
Iteration 2: lo=0, hi=3, mid=1, a[mid]=3
3 < 7 => search right half. lo = mid+1 = 2.
[1, 3] [5, 7]
lo=2 hi=3
Iteration 3: lo=2, hi=3, mid=2, a[mid]=5
5 < 7 => lo = mid+1 = 3.
[7]
lo=3=hi=3
Iteration 4: lo=3, hi=3, mid=3, a[mid]=7
7 == 7 => FOUND at index 3.
Total comparisons: 4 = ceil(log2(10)). Without binary search: up to 10.Diagram 2 — Lower Bound (First Occurrence)
Lower Bound and Upper Bound Trace
Array: [1, 3, 3, 3, 5, 7, 9] target = 3
Index: 0 1 2 3 4 5 6
Goal: find FIRST index where a[i] >= 3 (first occurrence of 3)
lo=0, hi=7 (n=7, one past end)
Iteration 1: mid=3, a[3]=3
3 >= target=3 => hi = mid = 3. (keep mid as candidate)
lo=0, hi=3
Iteration 2: mid=1, a[1]=3
3 >= 3 => hi = 1.
lo=0, hi=1
Iteration 3: mid=0, a[0]=1
1 < 3 => lo = mid+1 = 1.
lo=1, hi=1 => loop exits (lo == hi).
Return lo = 1. a[1] = 3 = first occurrence. Correct!
Upper bound (first index > 3): returns 4.
So all occurrences of 3 are in indices [1, 4) = {1, 2, 3}.
Count of 3s = upperBound - lowerBound = 4 - 1 = 3. Correct!Diagram 3 — Binary Search on Answer Space
Binary Search on Answer Space: Koko Bananas
Problem: Koko eats bananas. Piles = [3, 6, 7, 11]. H = 8 hours.
Find minimum eating speed k such that Koko finishes all piles in H hours.
Key insight: 'Can Koko finish at speed k?' is monotone.
If YES at speed k, then YES at speed k+1, k+2, ... (faster is always feasible).
If NO at speed k, then NO at speed k-1, k-2, ... (slower is never feasible).
=> Binary search on k!
Search space: lo=1 (min possible speed), hi=11 (max pile = always works).
mid=6: hours = ceil(3/6)+ceil(6/6)+ceil(7/6)+ceil(11/6) = 1+1+2+2 = 6 <= 8. YES
hi = 6.
mid=3: hours = ceil(3/3)+ceil(6/3)+ceil(7/3)+ceil(11/3) = 1+2+3+4 = 10 > 8. NO
lo = 4.
mid=5: hours = ceil(3/5)+ceil(6/5)+ceil(7/5)+ceil(11/5) = 1+2+2+3 = 8 <= 8. YES
hi = 5.
mid=4: hours = ceil(3/4)+ceil(6/4)+ceil(7/4)+ceil(11/4) = 1+2+2+3 = 8 <= 8. YES
hi = 4.
lo=4 == hi=4 => return 4.
Answer: minimum speed = 4. Correct!Diagram 4 — Rotated Sorted Array
Rotated Array: Which Half Is Sorted?
Original sorted: [1, 2, 3, 4, 5, 6, 7]
Rotated at index 3: [4, 5, 6, 7, 1, 2, 3]
Index: 0 1 2 3 4 5 6
Key property: at least ONE half is always normally sorted.
Check: if a[lo] <= a[mid] => left half [lo..mid] is sorted.
else => right half [mid..hi] is sorted.
Search for target = 1:
lo=0, hi=6, mid=3, a[mid]=7.
a[lo]=4 <= a[mid]=7 => LEFT half [0..3] = [4,5,6,7] is sorted.
Is target 1 in [4, 7]? 1 < 4 => NO. Search right: lo = 4.
lo=4, hi=6, mid=5, a[mid]=2.
a[lo]=1 <= a[mid]=2 => LEFT half [4..5] = [1,2] is sorted.
Is target 1 in [1, 2]? 1 >= 1 and 1 <= 2 => YES. Search left: hi = 5.
lo=4, hi=5, mid=4, a[mid]=1.
a[mid] == target => FOUND at index 4.Section 3 — Real-World Use Cases
| Application | System | How Binary Search Is Used |
|---|---|---|
| Dictionary / index lookup | Database B-Tree index | Search sorted key space in O(log n) I/O pages |
| Version control bisect | git bisect | Binary search through commit history to find first bad commit |
| IP routing | Network router lookup | Longest prefix match via binary search on sorted prefix table |
| Load balancing | Consistent hashing ring | Binary search for the next server on the sorted hash ring |
| Media streaming | Video player seek | Binary search on sorted timestamp index for O(log n) seek |
| Spell checker | Sorted dictionary file | Binary search for word existence / nearest match |
| Compression | Arithmetic / range coding | Binary search on cumulative frequency table |
| Scheduling | Rate limiter / throttle | Binary search on sorted event timestamps for window queries |
| Machine learning | Hyperparameter tuning | Binary / ternary search on unimodal loss curve |
| Scientific computing | Root finding | Bisection method: binary search for f(x)=0 in continuous domain |
Section 4 — Core Concepts & Algorithms
4.1 — Search in Rotated Sorted Array
// Rotated Sorted Array Search — O(log n)
// LeetCode 33 — Search in Rotated Sorted Array
// Time: O(log n) Space: O(1)
// Key: at mid, exactly one half is normally sorted. Use that to guide search.
int search(vector<int>& a, int target) {
int lo = 0, hi = (int)a.size() - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] == target) return mid;
// Determine which half is sorted
if (a[lo] <= a[mid]) { // left half [lo..mid] is sorted
if (a[lo] <= target && target < a[mid])
hi = mid - 1; // target is in sorted left half
else
lo = mid + 1; // target must be in right half
} else { // right half [mid..hi] is sorted
if (a[mid] < target && target <= a[hi])
lo = mid + 1; // target is in sorted right half
else
hi = mid - 1; // target must be in left half
}
}
return -1;
}4.2 — Find Minimum in Rotated Sorted Array
// Find Minimum in Rotated Array — O(log n)
// LeetCode 153 — Find Minimum in Rotated Sorted Array
// Time: O(log n) Space: O(1)
// The minimum is always in the UNSORTED (rotated) half.
int findMin(vector<int>& a) {
int lo = 0, hi = (int)a.size() - 1;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] > a[hi])
lo = mid + 1; // min is in right half (right is unsorted)
else
hi = mid; // min is in left half or at mid
}
return a[lo]; // lo == hi == index of minimum
}
// Why compare with a[hi] not a[lo]?
// Comparing mid to hi tells us if the right side is 'out of order' (rotated).
// If a[mid] > a[hi]: right half wraps around, minimum is in [mid+1, hi].
// If a[mid] <= a[hi]: right half is sorted normally, minimum is in [lo, mid].4.3 — Binary Search on Answer Space
Many optimisation problems can be solved by binary searching on the answer value directly. The key insight: define a feasibility function f(x) that returns true/false. If f is monotone (all true for x >= answer, all false below), binary search finds the boundary.
// Binary Search on Answer Space — O(n log(max_val))
// Generic answer-space binary search template
// Find minimum x such that feasible(x) is true.
int answerSpaceBS(int lo, int hi) {
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (feasible(mid))
hi = mid; // mid works, try smaller
else
lo = mid + 1; // mid does not work, must go larger
}
return lo; // minimum feasible value
}
// Koko Eating Bananas (LC 875)
// feasible(k): can Koko eat all piles at speed k in H hours?
bool feasible(vector<int>& piles, int k, int H) {
long long hours = 0;
for (int p : piles) hours += (p + k - 1) / k; // ceil(p/k)
return hours <= H;
}
int minEatingSpeed(vector<int>& piles, int h) {
int lo = 1, hi = *max_element(piles.begin(), piles.end());
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (feasible(piles, mid, h)) hi = mid;
else lo = mid + 1;
}
return lo;
}4.4 — Counting Occurrences with Lower/Upper Bound
// Lower/Upper Bound Applications
// Count occurrences of target in sorted array
// Time: O(log n) Space: O(1)
int countOccurrences(vector<int>& a, int target) {
// lower_bound: first index with a[i] >= target
int lo = (int)(lower_bound(a.begin(), a.end(), target) - a.begin());
// upper_bound: first index with a[i] > target
int hi = (int)(upper_bound(a.begin(), a.end(), target) - a.begin());
return hi - lo; // number of elements equal to target
}
// First and last position of target (LC 34)
vector<int> searchRange(vector<int>& a, int target) {
int first = (int)(lower_bound(a.begin(),a.end(),target) - a.begin());
if (first == (int)a.size() || a[first] != target) return {-1,-1};
int last = (int)(upper_bound(a.begin(),a.end(),target) - a.begin()) - 1;
return {first, last};
}4.5 — Binary Search on 2D Matrix
// Binary Search on 2D Matrix — O(log(mn)) and O(m+n)
// LeetCode 74 — Search a 2D Matrix
// Matrix: rows sorted, last element of row < first element of next row.
// => Treat as a flattened 1D sorted array of m*n elements.
// Time: O(log(m*n)) Space: O(1)
bool searchMatrix(vector<vector<int>>& mat, int target) {
int m = mat.size(), n = mat[0].size();
int lo = 0, hi = m * n - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
int val = mat[mid / n][mid % n]; // convert 1D index to 2D
if (val == target) return true;
else if (val < target) lo = mid + 1;
else hi = mid - 1;
}
return false;
}
// LeetCode 240 — Search a 2D Matrix II
// Each row sorted, each column sorted (but rows don't connect).
// Use staircase search from top-right corner: O(m+n)
bool searchMatrixII(vector<vector<int>>& mat, int target) {
int r = 0, c = (int)mat[0].size() - 1; // start top-right
while (r < (int)mat.size() && c >= 0) {
if (mat[r][c] == target) return true;
else if (mat[r][c] > target) c--; // too big: move left
else r++; // too small: move down
}
return false;
}Section 5 — Pattern Recognition Guide
| If the problem asks... | Binary Search Variant | Key Setup |
|---|---|---|
| Find exact value in sorted array | Classic (Template 1) | lo=0, hi=n-1, lo<=hi |
| First position of target (or >= target) | Lower bound (Template 2) | lo=0, hi=n, lo<hi |
| Last position of target | Upper bound - 1 | upperBound(target) - 1 |
| Count occurrences of target | upperBound - lowerBound | Both in O(log n) |
| Search in rotated sorted array | Rotated BS | Identify sorted half at each step |
| Find minimum in rotated array | Compare mid to hi | Minimum is in unsorted half |
| Minimum feasible value (Koko, capacity) | Answer space BS | Binary search on answer, check feasibility |
| Maximum feasible value | Answer space BS (reversed) | Flip condition: search for last true |
| Peak element in array | Binary search on slope | Move toward the higher neighbour |
| Square root / power search | Answer space BS | lo=1, hi=target, check mid*mid |
| Search in 2D matrix (rows+cols connected) | Flatten to 1D | index (r,c) = (mid/n, mid%n) |
| Search in 2D matrix (rows+cols sorted) | Staircase from top-right | O(m+n), not binary search |
- SIGNAL 1: The problem asks for a minimum or maximum VALUE satisfying some condition.
- SIGNAL 2: You can define a yes/no feasibility function
f(x)that is monotone (all NO below threshold, all YES above). - SIGNAL 3: Keywords: 'minimise the maximum', 'maximum minimum', 'smallest k such that', 'allocate optimally'.
- SETUP:
lo= smallest possible answer,hi= largest possible answer (often max element or sum). - DIRECTION: minimise answer -> on feasible, go left (
hi=mid). Maximise answer -> on feasible, go right (lo=mid). - EXAMPLES: Koko Bananas, Capacity to Ship Packages, Split Array Largest Sum, Magnetic Force Between Balls.
- Use
lo + (hi - lo) / 2always — never(lo + hi) / 2. Avoids integer overflow. - Classic search (exact):
lo <= hi, updatelo=mid+1orhi=mid-1. - Boundary search (lower/upper bound):
lo < hi, updatelo=mid+1orhi=mid(NOTmid-1!). hi = n(notn-1) for lower/upper bound — allows returningn(insert at end).- Never set
hi = mid - 1in a lower-bound template — you will skip the answer. - After the loop:
lo == hi== the answer index. No need to check both.
Section 6 — Complete C++ Implementations
6.1 — Capacity to Ship Packages (Answer Space BS)
// Capacity to Ship — O(n log sum)
// LeetCode 1011 — Capacity to Ship Packages Within D Days
// Find minimum ship capacity to deliver all packages within D days.
// Time: O(n log(sum)) Space: O(1)
class Solution {
bool canShip(vector<int>& weights, int cap, int days) {
int d = 1, load = 0;
for (int w : weights) {
if (load + w > cap) { d++; load = 0; } // start new day
load += w;
}
return d <= days;
}
public:
int shipWithinDays(vector<int>& weights, int days) {
// lo: must hold heaviest package; hi: ship all at once
int lo = *max_element(weights.begin(), weights.end());
int hi = accumulate(weights.begin(), weights.end(), 0);
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (canShip(weights, mid, days)) hi = mid;
else lo = mid + 1;
}
return lo;
}
};6.2 — Find Peak Element
// Find Peak Element — O(log n)
// LeetCode 162 — Find Peak Element
// A peak is an element strictly greater than its neighbours.
// Time: O(log n) Space: O(1)
// Key insight: always move toward the higher neighbour.
// A peak must exist in that direction (by the rising slope argument).
int findPeakElement(vector<int>& a) {
int lo = 0, hi = (int)a.size() - 1;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] < a[mid+1])
lo = mid + 1; // slope going up: peak is to the right
else
hi = mid; // slope going down: peak is at mid or left
}
return lo; // lo == hi == index of a peak
}6.3 — Split Array Largest Sum
// Split Array Largest Sum — O(n log sum)
// LeetCode 410 — Split Array Largest Sum
// Split nums into k non-empty subarrays to minimise the largest subarray sum.
// Time: O(n log(sum)) Space: O(1)
class Solution {
bool canSplit(vector<int>& nums, int k, int limit) {
int parts = 1, curr = 0;
for (int x : nums) {
if (curr + x > limit) { parts++; curr = 0; }
curr += x;
}
return parts <= k;
}
public:
int splitArray(vector<int>& nums, int k) {
int lo = *max_element(nums.begin(), nums.end());
int hi = accumulate(nums.begin(), nums.end(), 0);
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (canSplit(nums, k, mid)) hi = mid;
else lo = mid + 1;
}
return lo;
}
};Section 7 — Complexity Reference
| Algorithm | Time | Space |
|---|---|---|
| Classic binary search (exact) | O(log n) | O(1) |
| Lower bound / upper bound | O(log n) | O(1) |
| First and last position of target | O(log n) | O(1) |
| Search in rotated sorted array | O(log n) | O(1) |
| Find minimum in rotated array | O(log n) | O(1) |
| Find peak element | O(log n) | O(1) |
| Koko bananas / eating speed | O(n log M) M = max pile | O(1) |
| Capacity to ship (D days) | O(n log S) S = sum | O(1) |
| Split array largest sum | O(n log S) S = sum | O(1) |
| Search in 2D matrix (LC 74) | O(log(m*n)) | O(1) |
| Search in 2D matrix II (LC 240) | O(m + n) | O(1) |
| Count occurrences (lower+upper) | O(log n) | O(1) |
| Square root integer | O(log n) | O(1) |
- Each iteration halves the search window:
n -> n/2 -> n/4 -> ... -> 1. - After
kiterations, window size =n / 2^k. Loop ends whenn / 2^k = 1, sok = log2(n). - For
n = 10^9:log2(10^9) ~ 30iterations. Linear search would need up to10^9. - Answer-space binary search:
O(log(hi-lo))iterations *O(feasibility check)per iteration. - If feasibility check is
O(n), total isO(n log(hi-lo)). For Koko:O(n log(max_pile)).
Section 8 — Solved Problem 1: Search in Rotated Sorted Array
Given an integer array nums sorted in ascending order that has been rotated at an unknown pivot, and a target value, return the index of target or -1 if not present. Must run in O(log n).
- A rotated sorted array like
[4,5,6,7,0,1,2]is NOT globally sorted, so naive binary search fails. - Key insight: Even after rotation, at least one of the two halves
[lo..mid]or[mid..hi]is ALWAYS sorted normally. We can determine which by comparinga[lo]witha[mid]. - If
a[lo] <= a[mid]: the left half[lo..mid]is sorted. Check if target falls within[a[lo], a[mid]). If yes, search left; otherwise search right. - If
a[lo] > a[mid]: the right half[mid..hi]is sorted. Check if target falls within(a[mid], a[hi]]. If yes, search right; otherwise search left.
2. Approach Comparison
| Approach | Time | Space | Method |
|---|---|---|---|
| Linear Scan | O(n) | O(1) | Check every element until found. |
| Rotated Binary Search | O(log n) | O(1) | Identify sorted half, eliminate half array per step. |
3. Optimised Solution
class Solution {
public:
int search(vector<int>& nums, int target) {
int lo = 0, hi = (int)nums.size() - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (nums[mid] == target) return mid;
if (nums[lo] <= nums[mid]) {
// Left half [lo..mid] is sorted
if (nums[lo] <= target && target < nums[mid])
hi = mid - 1; // target in sorted left half
else
lo = mid + 1; // target in right half
} else {
// Right half [mid..hi] is sorted
if (nums[mid] < target && target <= nums[hi])
lo = mid + 1; // target in sorted right half
else
hi = mid - 1; // target in left half
}
}
return -1;
}
};4. Follow-Up Questions
- Q: What if the array has duplicates (LC 81)? When
a[lo] == a[mid], we cannot determine which half is sorted. Incrementlo(lo++) to skip the duplicate and continue. Worst case degrades to O(n). - Q: Find the pivot index? Binary search for the minimum element (LC 153). The pivot is the index of the minimum.
- Q: Why use
a[lo] <= a[mid]instead of<? Whenlo == mid(two-element window),a[lo] == a[mid]and the left half of size 1 is trivially sorted. The<=safely handles this.
Section 9 — Solved Problem 2: Koko Eating Bananas
Koko has piles of bananas. She eats at speed k (k bananas per hour). Each hour she picks one pile and eats min(pile, k) bananas. Find the minimum k so she can eat all bananas in at most h hours.
- For a given speed
k, hours needed = sum ofceil(pile[i] / k)over all piles. - Monotone property: If speed
kis feasible, then any speedk' > kis also feasible. This enables binary search onk. - Search space:
lo = 1,hi = max(piles). - Binary search finds the minimum
kwherefeasible(k)is true. This is the lower-bound template on the answer space.
2. Approach Comparison
| Approach | Time | Space | Method |
|---|---|---|---|
| Brute Force (Linear Scan) | O(n * M) | O(1) | Try every speed from 1 to M (max pile). |
| Binary Search on Answer | O(n log M) | O(1) | Binary search lo to hi boundary. |
3. Optimised Solution
class Solution {
// Can Koko finish all piles at speed k within h hours?
bool feasible(vector<int>& piles, long long k, int h) {
long long hours = 0;
for (int p : piles)
hours += (p + k - 1) / k; // ceil(p / k)
return hours <= h;
}
public:
int minEatingSpeed(vector<int>& piles, int h) {
int lo = 1;
int hi = *max_element(piles.begin(), piles.end());
// Binary search: find minimum k where feasible(k) is true
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (feasible(piles, mid, h))
hi = mid; // mid works, try smaller
else
lo = mid + 1; // mid too slow, need faster
}
return lo; // lo == hi == minimum feasible speed
}
};4. Follow-Up Questions
- Q: Capacity to Ship Packages (LC 1011)? Identical structure.
feasible(cap): simulate loading, increment day.lo = max weight,hi = sum of weights. - Q: Split Array Largest Sum (LC 410)? Same template.
lo = max element,hi = total sum. - Q: Why
ceil(p/k) = (p + k - 1) / k? In integer math for positive integersaandb,ceil(a/b) = (a + b - 1) / b. Verify:ceil(7/3) = (7+2)/3 = 9/3 = 3.
Section 10 — Common Mistakes & Edge Cases
10.1 — Classic Off-By-One Errors
- MISTAKE: Using (lo + hi) / 2. When lo and hi are both large, lo + hi overflows a 32-bit integer. Always use
lo + (hi - lo) / 2. - MISTAKE: Using hi = mid - 1 in a lower-bound template. If mid is the answer, this skips it. Lower-bound must use
hi = mid. - MISTAKE: Using lo <= hi in a lower-bound search. This can loop forever when lo == hi. Lower-bound uses
lo < hi. - MISTAKE: Initialising hi = n - 1 for lower/upper bound. The answer can be n (insert at end). Always initialise
hi = n.
10.2 — Rotated Array & Answer Space Mistakes
- MISTAKE: strict less in rotated array search: using
a[lo] < a[mid]instead of<=. Fails on a two-element window. - MISTAKE: integer overflow in feasibility check. Use
long longfor accumulated sums or counts (like hours needed for Koko). - MISTAKE: confusing minimise vs maximise answer space. Draw the YES/NO monotone map. If you want the first YES (minimise), use
hi = midon YES. If you want the last YES (maximise), uselo = midon YES.
Edge Cases to Consider:
- Single-element array:
lo==hi==mid. Classic search works. - All elements equal (e.g.
[3,3,3]):lower_boundreturns 0,upper_boundreturns n. - Target larger than all elements:
lower_boundandupper_boundboth return n.
Section 11 — Common Interview Questions
Recommended progression for Binary Search:
| # | Problem | Difficulty | Key Concept |
|---|---|---|---|
| 1 | 704. Binary Search | Easy | Template 1, exact search |
| 2 | 35. Search Insert Position | Easy | Lower bound, return lo |
| 3 | 34. Find First and Last Position | Medium | Lower + upper bound |
| 4 | 33. Search in Rotated Sorted Array | Medium | Identify sorted half |
| 5 | 153. Find Minimum in Rotated Sorted Array | Medium | Compare mid to hi |
| 6 | 74. Search a 2D Matrix | Medium | Flatten to 1D binary search |
| 7 | 875. Koko Eating Bananas | Medium | Answer space: minimise |
| 8 | 1011. Capacity to Ship Packages | Medium | Answer space: min capacity |