DSA Patterns: Binary Search

Table of contents
- π Binary Search Pattern β The Interviewer's Favorite
- π§ TL;DR - What to Focus On
- Introduction
- π When to Use Binary Search
- βοΈ The Two Faces of Binary Search
- π§° Core Binary Search Template
- π§ Core Template: Binary Search on Answer
- π§ How to Recognize & Apply Binary Search on Answer
- π§ͺ Use Cases & Problem Templates
- π§ Key Takeaways
- Conclusion
π Binary Search Pattern β The Interviewer's Favorite
π§ TL;DR - What to Focus On
This guide is long β but structured. Use the Table of Contents (TOC) as your best friend to glance, skim, or jump around. Here's where to go based on your goal:
β
Just want the templates and patterns?
β Jump to π§ͺ Use Cases & Problem Templates
Includes 5 reusable binary search patterns with Java code and dry runs.
β οΈ Keep messing up edge cases or stuck in infinite loops?
β Read β Common Pitfalls: Infinite Loops and Off-by-One Errors
Covers loop conditions, shrinking logic, and off-by-one traps that haunt beginners.
π€― Struggling with "Binary Search on Answer" problems?
β Start with π§ Core Template: Binary Search on Answer
β Then go through π§ How to Recognize & Apply Binary Search on Answer
β Learn by example via Template 4 and Template 5
π§ Want a high-level recap at the end? β Skip to π§ Key Takeaways
Introduction
Binary Search helps cut down search space logarithmically by halving the range each time. It works best when you're dealing with:
- A sorted array, or
A monotonic decision space (increasing/decreasing answers)
Instead of brute-forcing through every possibility, we jump straight to the middle, ask "too big or too small?" and shrink our space accordingly.
π When to Use Binary Search
Reach for this pattern when:
β
You're working with a sorted array
β
You're searching for a target value or threshold
β
You can define a βyes/noβ decision function to guide the direction
β
The answer lies in a range of values rather than an index
βοΈ The Two Faces of Binary Search
There are two major flavors of Binary Search you'll encounter:
1. Classic Index Binary Search
Works directly on a sorted array to locate a specific element (or its left/right boundary).
Examples:
- Exact search (find a number)
- Leftmost/rightmost position of target
- Insert position
2. Binary Search on Answer
You donβt binary search an array, but a range of potential answers. At each step, you ask:
βCan this value work as the answer?β
Then adjust your bounds based on a predicate.Examples:
- Minimum speed, capacity, time, or size
- Works when you can simulate and validate a guess
π§° Core Binary Search Template
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
This is the classic search in a sorted array.
Edge tweaks lead to all sorts of variants β leftmost, rightmost, first failing value, etc.
β Common Pitfalls: Infinite Loops and Off-by-One Errors
Binary Search is simple in theory β but off-by-one bugs and infinite loops haunt beginners. Letβs clear it up once and for all.
π Loop Conditions
Condition | Use When You... |
while (left <= right) | Want to check mid as a valid index (Classic style) |
while (left < right) | Want to stop at the first valid value (Answer style) |
β Never write: left = mid
or right = mid
β
Always shrink the range: left = mid + 1
or right = mid - 1
π₯ Why Infinite Loops Happen
They occur when your left
and right
donβt move.
Example mistake:
// β This can loop forever if mid == left
if (nums[mid] < target) left = mid;
Fix: Use left = mid + 1
to ensure the window shrinks.
π§ Mental Model: βAlways Shrink the Windowβ
Every iteration must cut off part of the search space.
If mid
doesn't eliminate anything, youβre stuck in a loop.
Before:
[ ... L ... M ... R ]
After:
[ ... L ... M ] β
or [ ... M ... R ] β
β [ ... L ... M ... R ] β window never shrinks
π§ Core Template: Binary Search on Answer
int left = MIN_POSSIBLE, right = MAX_POSSIBLE;
while (left < right) {
int mid = left + (right - left) / 2;
if (isValid(mid)) {
right = mid; Try smaller
} else {
left = mid + 1; Need larger
}
}
return left;
Note that in these problems:
- You donβt have an array
- You simulate a decision at
mid
using a predicate likeisValid(mid)
π§ How to Recognize & Apply Binary Search on Answer
Binary Search isn't just for sorted arrays β it shines in optimization problems too.
When you're not given a sorted array but are asked to minimize or maximize a value, you're likely in Binary Search on Answer territory.
π§ Step 1: Spot the Clues
These are the telltale signs youβre meant to binary search over the answer itself:
Clue | What It Looks Like |
β You're asked to minimize or maximize a number | βWhat is the minimum time to finishβ¦?β |
β You can βguess a number and check if it worksβ | Can simulate using isValid(mid) |
β Thereβs a monotonic relationship in your guesses | If 5 works, 6 might also work β or vice versa |
β You're not searching an array but a value range | Usually from 1 to max(input) |
β Brute force is too slow | Constraints are large (N = 10β΅), but value space is small |
π§ How to Build the Feasibility Function (isValid(mid)
)
This is the core trick of Binary Search on Answer:
You donβt know the answer, so you guess it, simulate the scenario, and ask:
βIf I set the answer to
mid
, can I make it work?β
β
Step 1: Treat mid
as a guess
This is the βwhat if?β moment.
- βWhat if Koko eats
mid
bananas per hour?β - βWhat if the ship has
mid
capacity?β - βWhat if I assign tasks with max load
mid
?β
β Step 2: Simulate based on the problem
Write a simulation that models the system using that mid
guess.
Can you:
- Finish in time?
- Fit everything in?
- Use valid number of splits/days?
β Step 3: Return true or false
If the simulation succeeds, mid
is feasible β you can try better
If it fails, it's too extreme β adjust your search accordingly
π§ͺ Example: Koko Eating Bananas
boolean isValid(int speed) {
int hours = 0;
for (int pile : piles) {
hours += Math.ceil((double) pile / speed);
}
return hours <= h;
}
- If speed is high β time taken is less β more likely to be valid
- Monotonic behavior β good for binary search
π§ͺ Example: Ship Packages in D Days
boolean isValid(int capacity) {
int days = 1, current = 0;
for (int weight : weights) {
if (current + weight > capacity) {
days++;
current = 0;
}
current += weight;
}
return days <= D;
}
- If capacity is high β you need fewer days β valid
- The more you increase capacity, the better it gets β again, monotonic
π Why Monotonicity Matters
Binary Search only works if:
All values left of X are invalid, and all values right of X are valid (or vice versa)
Thatβs what lets you cut the space in half and be confident.
π§ Summary: How to Think
βIf I guess this number, can I make it work?β
If yes β itβs feasible β try to optimize further
If no β guess again with a new range
π§ͺ Use Cases & Problem Templates
Letβs now explore this pattern across classic problems, one template per pattern.
Each one will include:
- πΉ Problem
- πΉ Goal
- πΉ What we would do
- πΉ Template code
- πΉ Step-by-step dry run
- π Followed by: Other problems that use the same approach with a twist
π Template #1: Classic Binary Search
Representative Problem: Binary Search β Leetcode #704
πΉ Problem
Given a sorted integer array nums
and an integer target
, return the index if the target is found. If not, return -1
.
πΉ Goal
Find the exact position of target
using binary search.
πΉ What we would do
Use the standard binary search template with left <= right
.
Keep narrowing the range by comparing nums[mid]
to target
.
πΉ Template Code
int search(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) return mid;
else if (nums[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
πΉ Dry Run
Input: nums = [-1, 0, 3, 5, 9, 12], target = 9
Initial: left = 0, right = 5
Step 1: mid = 2 β nums[2] = 3 β too small β left = 3
Step 2: mid = 4 β nums[4] = 9 β match! return 4
π Other Famous Problems Using This Template
π Peak Index in a Mountain Array (#852)
- Twist: You're not looking for an exact value β you're trying to find the peak in a mountain array (first increasing, then decreasing).
- Observation: If
nums[mid] > nums[mid + 1]
, you're in the descending half, so the peak lies on the left side or at mid. - Else, you're in the ascending half, so move right.
- Same binary search structure, but guided by slope direction, not equality.
π Find Minimum in Rotated Sorted Array (#153)
- Twist: The array is sorted but rotated, so itβs not fully monotonic. Youβre trying to find the minimum element, not a target.
- Key idea: One half of the array is always sorted. Compare
nums[mid]
withnums[right]
to decide which half contains the minimum. - If
nums[mid] > nums[right]
, the min must be to the right of mid. - If
nums[mid] <= nums[right]
, the min could be at or to the left of mid. - Still classic binary search logic: shrink your bounds based on comparisons.
π Guess Number Higher or Lower (#374)
- Twist: You donβt access the array directly β instead, you get feedback via an API (
guess(mid)
returns -1/0/1). - It behaves exactly like a binary search comparator:
0
β target found-1
β guess is too high1
β guess is too low
- It's a textbook binary search β only difference is using an external check instead of direct comparison.
π Template #2: Search Insert Position
Representative Problem: Search Insert Position β Leetcode #35
πΉ Problem
Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
πΉ Goal
Find the correct position to insert target
such that array remains sorted.
πΉ What we would do
Weβre not just checking for equality β we need the first position β₯ target.
So, we donβt stop when we find the target β we keep shrinking towards the left boundary.
Use left < right
style binary search to converge on the correct index.
πΉ Template Code
int searchInsert(int[] nums, int target) {
int left = 0, right = nums.length;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] < target) left = mid + 1;
else right = mid;
}
return left;
}
πΉ Dry Run
Input: nums = [1, 3, 5, 6], target = 5
Initial: left = 0, right = 4
Step 1: mid = 2 β nums[2] = 5 β right = 2
Step 2: mid = 1 β nums[1] = 3 β left = 2
left == right β return 2
β
Target found at index 2
Input: nums = [1, 3, 5, 6], target = 2
Initial: left = 0, right = 4
Step 1: mid = 2 β nums[2] = 5 β right = 2
Step 2: mid = 1 β nums[1] = 3 β right = 1
Step 3: mid = 0 β nums[0] = 1 β left = 1
left == right β return 1
β
Insert position for target = 2 is index 1
π Other Famous Problems Using This Template
π Search Insert Position (#35)
- This is the canonical example of
lower_bound
. - Find the index where target should be inserted β i.e., first element β₯ target.
π Smallest Letter Greater Than Target (#744)
- Twist: Find the next character strictly greater than the target.
- Equivalent to
upper_bound
β first element > target. - Wrap-around behavior handled using:
letters[left % n]
.
π Find Right Interval (#436)
- Twist: For each interval, find another interval starting at or after the current intervalβs end.
- You binary search over sorted start points β
lower_bound
logic on interval start.
π First and Last Position of Element in Sorted Array (#34)
- Twist: Combines both
lower_bound
andupper_bound
manually. - Binary search to find:
- First occurrence of target (left bound)
- First index > target, then subtract 1 for right bound
π Template #3: First and Last Position
Representative Problem: Find First and Last Position of Element in Sorted Array β Leetcode #34
πΉ Problem
Given a sorted array of integers and a target value, return the indices of the first and last occurrence of the target. If the target is not present, return [-1, -1].
πΉ Goal
Perform two binary searches:
- To find the leftmost index of target (first occurrence)
- To find the rightmost index of target (last occurrence)
πΉ What we would do
Use a modified binary search:
- For the first occurrence, keep shrinking right even after finding the target
- For the last occurrence, keep expanding right even after finding the target
This is essentially combining
lower_bound
andupper_bound - 1
.
πΉ Template Code
int[] searchRange(int[] nums, int target) {
int left = findBound(nums, target, true);
int right = findBound(nums, target, false);
return new int[]{left, right};
}
int findBound(int[] nums, int target, boolean first) {
int left = 0, right = nums.length - 1, result = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
result = mid;
if (first) right = mid - 1;
else left = mid + 1;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
πΉ Dry Run
Input: nums = [5, 7, 7, 8, 8, 10], target = 8
First pass (first = true):
Initial: left = 0, right = 5
Step 1: mid = 2 β nums[2] = 7 β left = 3
Step 2: mid = 4 β nums[4] = 8 β result = 4, right = 3
Step 3: mid = 3 β nums[3] = 8 β result = 3, right = 2
Ends: left = 3, right = 2 β left bound = 3
Second pass (first = false):
Initial: left = 0, right = 5
Step 1: mid = 2 β nums[2] = 7 β left = 3
Step 2: mid = 4 β nums[4] = 8 β result = 4, left = 5
Step 3: mid = 5 β nums[5] = 10 β right = 4
Ends: left = 5, right = 4 β right bound = 4
Output: [3, 4]
π Other Famous Problems Using This Template
π [Count Occurrences of a Number in Sorted Array β Binary Search Variant]
- Not an official Leetcode title, but the technique is used in multiple places.
- Run
findBound(..., true)
andfindBound(..., false)
- Count = (right - left) + 1 if both bounds are valid.
π [Number of Occurrences of a Number in a Sorted Array β Similar to GFG/LC Explore cards]
- Same binary search twice β one for left boundary, one for right boundary.
- Used inside frequency-based search problems and subarray counting variations.
- Twist: Instead of a target value, youβre given a
isBadVersion(mid)
API. - The goal is to find the first position where the condition becomes true β like a custom
lower_bound
. - One binary search to find the earliest valid index.
π Template #4: Binary Search on Answer
Representative Problem: Koko Eating Bananas β Leetcode #875
πΉ Problem
Koko has piles[]
of bananas and h
hours to finish them.
Each hour, she picks one pile and eats up to k
bananas (k is the speed you pick).
If a pile has fewer than k
, she eats the whole pile and waits till next hour.
Return the minimum integer speed k
so she can eat all bananas in h
hours.
πΉ Goal
Find the smallest possible speed k
such that total eating time β€ h
.
πΉ What we would do
This is the classic Binary Search on Answer pattern:
- You're not given a sorted array, but you can guess an answer (a speed)
- You simulate that guess using a function like
canEatAll(k)
- The faster Koko eats, the fewer hours she takes β monotonic decreasing function
- Use binary search over the speed range
1
tomax(piles)
πΉ Template Code
int minEatingSpeed(int[] piles, int h) {
int low = 1, high = Arrays.stream(piles).max().getAsInt();
while (low < high) {
int mid = (low + high) / 2;
if (canEatAll(piles, h, mid)) {
high = mid; // Try smaller speed
} else {
low = mid + 1; // Need more speed
}
}
return low;
}
boolean canEatAll(int[] piles, int h, int speed) {
int hours = 0;
for (int pile : piles) {
hours += (pile + speed - 1) / speed; // Ceil division
}
return hours <= h;
}
πΉ Dry Run
Input: piles = [3, 6, 7, 11], h = 8
Speed search range: 1 to 11
We want the **minimum speed** that works.
Step 1: mid = (1 + 11) / 2 = 6
Total hours: 1 + 1 + 2 + 2 = 6 β
valid β try smaller β high = 6
Step 2: mid = (1 + 6) / 2 = 3
Total hours: 1 + 2 + 3 + 4 = 10 β too much β low = 4
Step 3: mid = (4 + 6) / 2 = 5
Hours: 1 + 2 + 2 + 3 = 8 β
valid β high = 5
Step 4: mid = (4 + 5) / 2 = 4
Hours: 1 + 2 + 2 + 3 = 8 β
valid β high = 4
low == high β return 4 β
Answer: 4
π Other Famous Problems Using This Template
π Capacity To Ship Packages in D Days (#1011)
- You binary search over ship capacity, and use
canShip(capacity)
to simulate shipping timeline.
π Split Array Largest Sum (#410)
- Binary search over possible largest subarray sums.
- Feasibility check is whether you can split array into
k
parts without exceeding that sum.
π Minimum Number of Days to Make m Bouquets (#1482)
- You guess a day, and check if itβs possible to form
m
bouquets of sizek
. - Binary search over days, with a bloom check.
π Find the Smallest Divisor Given a Threshold (#1283)
- Find the minimum divisor such that sum of ceiling divisions β€ threshold.
π [Aggressive Cows (GFG / InterviewBit)]
- Maximize the minimum distance between cows.
- Use binary search on distance, and place cows greedily to check feasibility.
π Template #5: Binary Search on Real Numbers (Precision Search)
Sometimes the problem asks for a decimal answer with precision, like square root or speed with floating-point constraints.
In such problems:
- Youβre not dealing with integers
- You canβt use
left < right
because floats never truly βmeetβ - You fix it by running the loop for a number of iterations (usually 100)
πΉ Problem
Return the square root of n
as a decimal accurate to 5β6 digits.
πΉ What we would do
- Binary search in the range [0, n]
- For each guess
mid
, check:mid * mid <= n
- Move
left
orright
based on that - After ~100 steps,
left
will be close to βn
πΉ Template Code
double sqrt(int n) {
double left = 0, right = n, mid = 0;
for (int i = 0; i < 100; i++) {
mid = (left + right) / 2.0;
if (mid * mid > n) {
right = mid; // Too big, shrink from right
} else {
left = mid; // Too small or just right, move up
}
}
return left;
}
πΉ Dry Run (n = 10)
We want to compute β10 β 3.16227
Initial: left = 0.0, right = 10.0
Iteration 1:
mid = 5.0 β 5*5 = 25 > 10 β shrink right β right = 5.0
Iteration 2:
mid = 2.5 β 2.5*2.5 = 6.25 < 10 β grow left β left = 2.5
Iteration 3:
mid = 3.75 β 14.06 > 10 β shrink right β right = 3.75
Iteration 4:
mid = 3.125 β 9.77 < 10 β grow left β left = 3.125
Iteration 5:
mid = 3.4375 β 11.82 > 10 β shrink right β right = 3.4375
Iteration 6:
mid = 3.28125 β 10.76 > 10 β shrink right β right = 3.28125
Iteration 7:
mid = 3.203125 β 10.25 > 10 β shrink right β right = 3.203125
Iteration 8:
mid = 3.1640625 β 10.01 > 10 β shrink right β right = 3.1640625
Iteration 9:
mid = 3.14453125 β 9.89 < 10 β grow left β left = 3.14453125
...
(This continues for 100 iterations, zooming in on β10)
Final left β 3.16227 β
π Youβll eventually converge to a value where
mid * mid
is extremely close ton
(like9.9999996
forn = 10
), accurate to 5β6 decimal places.
π Other Famous Problems Using This Template
π Minimum Speed to Arrive on Time (#1870)
- Problem: Youβre given distances and a total time limit. You must return the minimum integer speed that allows you to arrive on time.
- What weβre searching for: The smallest speed
s
such that total travel time β€hour
. - Feasibility Check: Simulate time = sum of
ceil(dist[i] / s)
for all but last leg, and exact for last leg. - Why itβs binary search: Higher speed β less time β monotonic decreasing function.
- Decimal twist: If
hour
is not an integer (e.g. 1.5), weβre essentially comparing float sums, which means we must handle floating point error carefully.
π Kth Smallest Distance Pair (#719)
- Problem: Given an array, return the k-th smallest absolute difference between any two elements.
- What weβre searching for: The smallest distance
d
such that there are at leastk
pairs with diff β€d
. - Feasibility Check: For each
mid
guess (distance), use two pointers to count number of valid pairs with distance β€mid
. - Why itβs binary search: As distance
d
increases, the number of valid pairs also increases β monotonic relationship. - Why real number template applies: In some variations, especially with coordinates or weights, the distances can be floating points. Youβd binary search over decimal distances with precision.
π [Find Square Root of a Number β GFG / Custom Inputs]
- Problem: Return the square root of a non-negative number
n
with decimal precision. - What weβre searching for: A
double
valuex
such thatx * x
is as close ton
as possible. - Feasibility Check: If
x * x > n
, youβre too high β shrink right. Otherwise, grow left. - Why itβs binary search: Itβs a classic case where we use binary search on a continuous domain (
double
) instead of an array. - Why use 100 iterations: Because floating point precision is tricky, instead of checking exact equality, we loop a fixed number of times to guarantee convergence.
π§ Think: βDecimal answer? Fixed number of steps. Shrink the range slowly.β
π§ Key Takeaways
Here are the 5 most important things to master about Binary Search for coding interviews:
π Binary Search β Only Searching Arrays
It's a mindset β use it to search over answers, floats, or any monotonic space, not just array indices.π― Master the 5 Core Templates
Know when to use:- Classic index lookup
- Insert position
- Left/right boundary
- Binary Search on Answer
- Precision-based (decimal) binary search
β οΈ Loop Boundaries Matter More Than You Think
Understand the difference betweenleft <= right
andleft < right
, and never writeleft = mid
.π§ͺ "Binary Search on Answer" Is the Real Interview MVP
Use it when you're asked to minimize/maximize under a constraint β like speed, time, load, capacity, etc.
ImplementisValid(mid)
to guide the search.π§ Dry Run Edge Cases Like a Pro
Interviewers love corner cases. Always dry run:- Empty input
- Single-element arrays
- Target not found
- Off-by-one traps in even/odd length inputs
Conclusion
Once solid with this pattern, you can start spotting it in problems that donβt even look like binary search problems at first. Hope this helps internalize/revise Binary Search pattern for interviews!
Subscribe to my newsletter
Read articles from LilSardarX directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

LilSardarX
LilSardarX
Iβm figuring things out in tech β and blogging along the way. I write what I learn, so I can revise it later and maybe help you avoid a few rabbit holes.