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 2: Lower bound ──────────────────────────────────
// Use when: find first index where a[i] >= target.
// Loop exits when lo == hi == insertion point.
int lowerBound(vector
// ── TEMPLATE 3: Upper bound ──────────────────────────────────
// Use when: find first index where a[i] > target.
int upperBound(vector
</div>
<h3 class="section-subheading">1.2 — Template Comparison</h3>
<div class="ch-ed-problems">
<table>
<thead>
<tr><th>Template</th><th>Loop Condition</th><th><code>hi</code> initialised to</th><th><code>lo/hi</code> Update</th><th>Returns</th></tr>
</thead>
<tbody>
<tr><td>Classic exact</td><td><code>lo <= hi</code></td><td><code>n - 1</code></td><td><code>lo=mid+1</code> or <code>hi=mid-1</code></td><td>Index or <code>-1</code></td></tr>
<tr><td>Lower bound</td><td><code>lo < hi</code></td><td><code>n</code></td><td><code>lo=mid+1</code> or <code>hi=mid</code></td><td>First idx >= target</td></tr>
<tr><td>Upper bound</td><td><code>lo < hi</code></td><td><code>n</code></td><td><code>lo=mid+1</code> or <code>hi=mid</code></td><td>First idx > target</td></tr>
<tr><td>Answer space</td><td><code>lo < hi</code> or <code><=</code></td><td>problem max</td><td>depends on feasibility</td><td>Optimal value</td></tr>
</tbody>
</table>
</div>
</div>
<!-- Section 2 -->
<div class="chapter-section">
<h2 class="section-heading">Section 2 — Visual Diagrams: Binary Search in Action</h2>
<h3 class="section-subheading">Diagram 1 — Classic Binary Search</h3>
<div class="ch-code-wrap">
<span class="ch-code-label">Trace</span>
```text
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)
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!
</div>
<h3 class="section-subheading">Diagram 3 — Binary Search on Answer Space</h3>
<div class="ch-code-wrap">
<span class="ch-code-label">Trace</span>
```text
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
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.
</div>
</div>
<!-- Section 3 -->
<div class="chapter-section">
<h2 class="section-heading">Section 3 — Real-World Use Cases</h2>
<div class="ch-ed-problems">
<table>
<thead>
<tr><th>Application</th><th>System</th><th>How Binary Search Is Used</th></tr>
</thead>
<tbody>
<tr><td>Dictionary / index lookup</td><td>Database B-Tree index</td><td>Search sorted key space in O(log n) I/O pages</td></tr>
<tr><td>Version control bisect</td><td><code>git bisect</code></td><td>Binary search through commit history to find first bad commit</td></tr>
<tr><td>IP routing</td><td>Network router lookup</td><td>Longest prefix match via binary search on sorted prefix table</td></tr>
<tr><td>Load balancing</td><td>Consistent hashing ring</td><td>Binary search for the next server on the sorted hash ring</td></tr>
<tr><td>Media streaming</td><td>Video player seek</td><td>Binary search on sorted timestamp index for O(log n) seek</td></tr>
<tr><td>Spell checker</td><td>Sorted dictionary file</td><td>Binary search for word existence / nearest match</td></tr>
<tr><td>Compression</td><td>Arithmetic / range coding</td><td>Binary search on cumulative frequency table</td></tr>
<tr><td>Scheduling</td><td>Rate limiter / throttle</td><td>Binary search on sorted event timestamps for window queries</td></tr>
<tr><td>Machine learning</td><td>Hyperparameter tuning</td><td>Binary / ternary search on unimodal loss curve</td></tr>
<tr><td>Scientific computing</td><td>Root finding</td><td>Bisection method: binary search for f(x)=0 in continuous domain</td></tr>
</tbody>
</table>
</div>
</div>
<!-- Section 4 -->
<div class="chapter-section">
<h2 class="section-heading">Section 4 — Core Concepts & Algorithms</h2>
<h3 class="section-subheading">4.1 — Search in Rotated Sorted Array</h3>
<div class="ch-code-wrap">
<span class="ch-code-label">C++</span>
```cpp
// 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
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.
// Koko Eating Bananas (LC 875)
// feasible(k): can Koko eat all piles at speed k in H hours?
bool feasible(vector
</div>
<h3 class="section-subheading">4.4 — Counting Occurrences with Lower/Upper Bound</h3>
<div class="ch-code-wrap">
<span class="ch-code-label">C++</span>
```cpp
// 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
// 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
</div>
</div>
<!-- Section 5 -->
<div class="chapter-section">
<h2 class="section-heading">Section 5 — Pattern Recognition Guide</h2>
<div class="ch-ed-problems">
<table>
<thead>
<tr><th>If the problem asks...</th><th>Binary Search Variant</th><th>Key Setup</th></tr>
</thead>
<tbody>
<tr><td>Find exact value in sorted array</td><td>Classic (Template 1)</td><td><code>lo=0, hi=n-1, lo<=hi</code></td></tr>
<tr><td>First position of target (or >= target)</td><td>Lower bound (Template 2)</td><td><code>lo=0, hi=n, lo<hi</code></td></tr>
<tr><td>Last position of target</td><td>Upper bound - 1</td><td><code>upperBound(target) - 1</code></td></tr>
<tr><td>Count occurrences of target</td><td><code>upperBound - lowerBound</code></td><td>Both in <code>O(log n)</code></td></tr>
<tr><td>Search in rotated sorted array</td><td>Rotated BS</td><td>Identify sorted half at each step</td></tr>
<tr><td>Find minimum in rotated array</td><td>Compare <code>mid</code> to <code>hi</code></td><td>Minimum is in unsorted half</td></tr>
<tr><td>Minimum feasible value (Koko, capacity)</td><td>Answer space BS</td><td>Binary search on answer, check feasibility</td></tr>
<tr><td>Maximum feasible value</td><td>Answer space BS (reversed)</td><td>Flip condition: search for last true</td></tr>
<tr><td>Peak element in array</td><td>Binary search on slope</td><td>Move toward the higher neighbour</td></tr>
<tr><td>Square root / power search</td><td>Answer space BS</td><td><code>lo=1, hi=target, check mid*mid</code></td></tr>
<tr><td>Search in 2D matrix (rows+cols connected)</td><td>Flatten to 1D</td><td><code>index (r,c) = (mid/n, mid%n)</code></td></tr>
<tr><td>Search in 2D matrix (rows+cols sorted)</td><td>Staircase from top-right</td><td><code>O(m+n)</code>, not binary search</td></tr>
</tbody>
</table>
</div>
<div class="insight-box">
<span class="insight-label">🔍 How to Identify an Answer-Space Binary Search Problem</span>
<ul>
<li><strong>SIGNAL 1:</strong> The problem asks for a minimum or maximum VALUE satisfying some condition.</li>
<li><strong>SIGNAL 2:</strong> You can define a yes/no feasibility function <code>f(x)</code> that is monotone (all NO below threshold, all YES above).</li>
<li><strong>SIGNAL 3:</strong> Keywords: 'minimise the maximum', 'maximum minimum', 'smallest k such that', 'allocate optimally'.</li>
<li><strong>SETUP:</strong> <code>lo</code> = smallest possible answer, <code>hi</code> = largest possible answer (often max element or sum).</li>
<li><strong>DIRECTION:</strong> minimise answer -> on feasible, go left (<code>hi=mid</code>). Maximise answer -> on feasible, go right (<code>lo=mid</code>).</li>
<li><strong>EXAMPLES:</strong> Koko Bananas, Capacity to Ship Packages, Split Array Largest Sum, Magnetic Force Between Balls.</li>
</ul>
</div>
<div class="insight-box">
<span class="insight-label">🛡️ The Off-By-One Survival Guide</span>
<ul>
<li>Use <code>lo + (hi - lo) / 2</code> always — never <code>(lo + hi) / 2</code>. Avoids integer overflow.</li>
<li>Classic search (exact): <code>lo <= hi</code>, update <code>lo=mid+1</code> or <code>hi=mid-1</code>.</li>
<li>Boundary search (lower/upper bound): <code>lo < hi</code>, update <code>lo=mid+1</code> or <code>hi=mid</code> (NOT <code>mid-1</code>!).</li>
<li><code>hi = n</code> (not <code>n-1</code>) for lower/upper bound — allows returning <code>n</code> (insert at end).</li>
<li>Never set <code>hi = mid - 1</code> in a lower-bound template — you will skip the answer.</li>
<li>After the loop: <code>lo == hi</code> == the answer index. No need to check both.</li>
</ul>
</div>
</div>
<!-- Section 6 -->
<div class="chapter-section">
<h2 class="section-heading">Section 6 — Complete C++ Implementations</h2>
<h3 class="section-subheading">6.1 — Capacity to Ship Packages (Answer Space BS)</h3>
<div class="ch-code-wrap">
<span class="ch-code-label">C++</span>
```cpp
// 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
6.3 — Split Array Largest Sum
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
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;
}
};
</div>
<h3 class="section-subheading">4. Follow-Up Questions</h3>
<ul>
<li><strong>Q: What if the array has duplicates (LC 81)?</strong> When <code>a[lo] == a[mid]</code>, we cannot determine which half is sorted. Increment <code>lo</code> (<code>lo++</code>) to skip the duplicate and continue. Worst case degrades to O(n).</li>
<li><strong>Q: Find the pivot index?</strong> Binary search for the minimum element (LC 153). The pivot is the index of the minimum.</li>
<li><strong>Q: Why use <code>a[lo] <= a[mid]</code> instead of <code><</code>?</strong> When <code>lo == mid</code> (two-element window), <code>a[lo] == a[mid]</code> and the left half of size 1 is trivially sorted. The <code><=</code> safely handles this.</li>
</ul>
</div>
<!-- Section 9 -->
<div class="chapter-section">
<h2 class="section-heading">Section 9 — Solved Problem 2: Koko Eating Bananas</h2>
<div class="insight-box">
<span class="insight-label">1. Observations & Core Idea</span>
<p>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.</p>
<ul>
<li>For a given speed <code>k</code>, hours needed = sum of <code>ceil(pile[i] / k)</code> over all piles.</li>
<li><strong>Monotone property:</strong> If speed <code>k</code> is feasible, then any speed <code>k' > k</code> is also feasible. This enables binary search on <code>k</code>.</li>
<li>Search space: <code>lo = 1</code>, <code>hi = max(piles)</code>.</li>
<li>Binary search finds the minimum <code>k</code> where <code>feasible(k)</code> is true. This is the lower-bound template on the answer space.</li>
</ul>
</div>
<h3 class="section-subheading">2. Approach Comparison</h3>
<div class="ch-ed-problems">
<table>
<thead>
<tr><th>Approach</th><th>Time</th><th>Space</th><th>Method</th></tr>
</thead>
<tbody>
<tr><td>Brute Force (Linear Scan)</td><td>O(n * M)</td><td>O(1)</td><td>Try every speed from 1 to M (max pile).</td></tr>
<tr><td>Binary Search on Answer</td><td>O(n log M)</td><td>O(1)</td><td>Binary search <code>lo</code> to <code>hi</code> boundary.</td></tr>
</tbody>
</table>
</div>
<h3 class="section-subheading">3. Optimised Solution</h3>
<div class="ch-code-wrap">
<span class="ch-code-label">C++</span>
```cpp
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 |