skip to content

Searching & Binary Search

Covers how to find things fast: linear search as the baseline, binary search as the interview canon, and the family of variants built on the same halving idea. Interviewers lean on this topic because binary search is short enough to probe precisely — a single off-by-one or a wrong boundary choice reveals whether you truly reason about invariants or just memorized a template.

part ofData structures & algorithmsoverview, primer and where to startread it →
on this pageshow

explore

questions

page 1 of 2

In a sorted array, what does a lower bound search return when the target value is absent?

level: juniorimportance: must knowfreq 72%

answer

  1. a miss here is not a failure
  2. the search still answers with a position
  3. think about where the value would slot in
  4. first element not smaller than the target
  5. valid answers run from 0 through n

basics

~20 s

A lower bound search returns the first index whose element is greater than or equal to the target. For an absent key that index is exactly where the value would be inserted to keep the array sorted. It never reports failure.

solid answer

~40 s

A lower bound search answers a positional question rather than a yes/no one: it returns the smallest index `i` such that `a[i] >= target`. When the target is present that is its first occurrence; when the target is absent it is the gap the value would slide into, so the array stays sorted — the insertion point. If every element is smaller than the target, the answer is `n`, the array length: a legal one-past-the-end insertion position, not an error. That is the key difference from an exact-match search, which has to invent a miss sentinel. Because the result is a position rather than a verdict, presence is a separate check: `i < n && a[i] == target`. The search itself is O(log n) comparisons and needs random access plus sorted order.

go deeper

for a junior

Be ready to state the definition crisply — first index whose element is at least the target — and to name the two edge answers, 0 and n. Screeners mostly want to hear that an absent key still gets a position.

for a middle

Explain why the result is a position rather than a verdict, and show the two-part presence check. An interviewer expects you to connect the returned index to keeping the array sorted after an insert.

for a senior

Show the production angle: the one-past-the-end return is a real out-of-bounds hazard in calling code, and bucketing values into ranges is the common case where no exact match ever occurs.

for a principal

Own the interface argument: a search that answers with a position composes into bucketing, insertion and range queries, while one that answers with a boolean forces every caller to re-derive the position.

## Two different questions Plain binary search asks: **is this value here?** A boundary search asks: **where does this value belong?** The second question is strictly more useful, and it is the one interview problems almost always want. The lower bound of a target in an array sorted ascending is defined as: > the smallest index `i` in `0..n` such that `a[i] >= target`, or `n` if no such index exists. Read it as *first index that is not below the target*. Nothing in that definition requires the target to be present. That is the whole point. ## The insertion point When the target is absent, the lower bound is the position at which you could insert the value and leave the array sorted. Everything before that index is strictly smaller; everything from that index on is strictly larger. Inserting between those two groups preserves order, which is exactly the definition of an insertion point. A worked example from a fee schedule. Tier thresholds, sorted ascending, are the minimum amounts at which each tier starts: ``` index: 0 1 2 3 4 threshold: 0 500 2000 10000 50000 ``` A transaction of 2000 is present at index 2 — the lower bound is 2. A transaction of 7500 is absent; the first threshold that is at least 7500 is 10000 at index 3, so the lower bound is 3. That tells you 7500 sits *between* the tier starting at 2000 and the tier starting at 10000, which is precisely the information the pricing code needs — and no exact match ever occurs for a realistic amount. ## The two edges The returned index ranges over `0..n` inclusive — `n + 1` possible answers, not `n`. Both endpoints are meaningful and both get fumbled: - **0** — every element is at least the target; the value belongs before everything. For an amount of -5 against the table above, the answer is 0. - **n** — every element is strictly smaller; the value belongs after everything. For an amount of 90000, the answer is 5, the array length. This is *not* an error and *not* a miss code. It is a valid insertion position that happens to be one past the last element. Callers who immediately read `a[i]` without checking `i < n` are reading out of bounds, and that is the single most common bug built on top of a correct bound. ## Presence is a separate question Because the result is always a position, it carries no information about whether the target was found. The check is two-part and both halves matter: ``` i = lowerBound(a, target) found = (i < length(a)) and (a[i] == target) ``` Omit the range test and you dereference past the end when the target exceeds everything. Omit the equality test and you claim every absent key is present. Candidates who assert "the search returns -1 when the key is missing" have imported the exact-match convention into a boundary search, where it does not apply — a bound has no miss to signal. ## Why a bound rather than an exact match Three everyday jobs are boundary jobs, not membership jobs: 1. **Bucketing a value into ranges** — the fee-tier case above. Membership is irrelevant; the gap is the answer. 2. **Maintaining a sorted collection** — you need the position before you can insert. 3. **Range queries** — the bounds of the target range delimit the slice you want, whether or not the endpoints themselves exist. All three are unanswerable with a boolean. Once you internalise that a boundary search returns a *place*, the family of variants stops looking like a pile of tricky loops and starts looking like one template with a swappable comparison. ## Preconditions and cost The array must be sorted by the same ordering the comparison uses, and the access pattern must be random access — halving a range is meaningless if reaching the midpoint costs a walk. The cost is O(log n) comparisons and O(1) extra space in the iterative form. Note carefully what that cost covers: *finding* the position. Actually placing an element there in an array is a separate, much more expensive operation, because the tail has to move. A final precision point: the bound is defined by the comparison, not by the presence of an element. Change `>=` to `>` and you get a different, equally well-defined position. That single-character degree of freedom is what generates the whole boundary family.

  • What does the search return when the target is larger than every element?
    It returns `n`, the array length. That is a legal one-past-the-end insertion position, not an error code — the value belongs after everything. Any caller that reads the element at the returned index must range-check first, because there is no element there. Treating `n` as a bug is how correct bounds get wrapped in broken code.
  • How do you tell from the returned index whether the target was actually present?
    Test both halves: `i < n` and `a[i] == target`. The bound alone cannot tell you — it returns a position for present and absent keys alike, and the position for an absent key looks identical to the position of a first occurrence. Skipping the range test reads out of bounds when the target exceeds everything.
  • Does an insertion point mean anything on an unsorted array?
    No. The whole result rests on the invariant that everything before the returned index is smaller and everything from it on is not. Without sorted order the halving step discards the wrong side, and the returned index is arbitrary rather than wrong in a detectable way — the search still terminates and still returns a number, which makes the bug quiet.

It is the difference between asking a librarian "do you have this book?" and asking "which shelf gap does it go in?" — the second question has an answer even when the book is missing.

saying these in an interview costs you the question

  • Says the search returns -1 when the key is absent
  • Treats the returned index as proof the target exists
  • Forgets the result can equal the array length
  • Reads the element at the returned index without a range check
  • Claims an insertion point requires the key to be present

context

open as a page

Why does a plain binary search return an arbitrary index when the sorted array holds duplicate keys?

level: juniorimportance: must knowfreq 74%

basics

~20 s

A plain binary search returns the moment a midpoint matches, so which member of a run of equal keys comes back depends only on where the splits fell. The leftmost occurrence requires searching on after a hit.

open as a page

Why does binary search need only about log2(n) comparisons where a linear scan needs n?

level: juniorimportance: must knowfreq 88%

basics

~20 s

Each comparison discards half of the remaining candidates, so the range shrinks n, n/2, n/4, down to one. The number of halvings needed to reach a single candidate is log2(n), so that many comparisons suffice.

open as a page

Why do binary search implementations compute mid as lo + (hi - lo) / 2 instead of (lo + hi) / 2?

level: juniorimportance: must knowfreq 70%

basics

~20 s

Adding lo and hi can overflow a fixed-width signed integer once indices grow large, wrapping negative and yielding an out-of-range midpoint. Computing lo + (hi - lo) / 2 keeps every intermediate value inside the valid index range.

open as a page

Why is linear search still O(n) even though it exits early on the first match?

level: juniorimportance: must knowfreq 80%

basics

~20 s

Linear search is O(n) because the bound is set by the worst case: a match in the last position, or no match at all, forces a scan of every element. Early exit improves lucky runs, not the growth rate.

open as a page

What does binary search return on a ledger sorted by id when you probe by amount?

level: juniorimportance: must knowfreq 78%

basics

~20 s

Nothing signals an error. The file is ordered by id but the search compares amounts, so each halving step discards the wrong half and returns an arbitrary index or a false "not present" — silent garbage, not an exception.

open as a page

What two different orderings can "sorted matrix" mean, and why does search differ?

level: juniorimportance: must knowfreq 70%

basics

~20 s

"Sorted matrix" means one of two things: fully sorted row-major, where the grid reads as one non-decreasing sequence and binary search costs O(log mn); or merely row- and column-sorted, which has no global order and needs corner elimination at O(m+n).

open as a page

Why can a binary-search-style method find a local maximum in an unsorted array?

level: juniorimportance: must knowfreq 60%

basics

~20 s

Binary search needs a rule that safely discards half the input, not sorted data. Comparing a sample with its right neighbour shows an uphill direction, and the uphill half always still contains a local maximum, so halving stays correct.

open as a page

Why does a standard binary search fail on a sorted array rotated by an unknown offset?

level: juniorimportance: must knowfreq 78%

basics

~20 s

Standard binary search assumes a total ascending order, so one comparison against the midpoint tells it which side to discard. Rotation breaks that assumption, so the discard rule can throw away the very half that holds the target.

open as a page

What is the time complexity of binary search on the answer, and why is it not O(log n)?

level: middleimportance: must knowfreq 62%

basics

~20 s

Binary search on the answer costs O(check) x O(log R), where R is the span of candidate answer VALUES. The log factor comes from the value range, not the input size, and the feasibility check usually dominates.

open as a page

Given a load limit, how do you check in one pass whether n contiguous batches fit k workers?

level: middleimportance: must knowfreq 65%

basics

~20 s

Sweep the batches in order, adding each to the current worker while its running load stays within the limit and opening a new worker otherwise, then report whether the worker count is at most k.

open as a page

Binary search with no array in memory: what makes searching an answer range valid?

level: middleimportance: must knowfreq 64%

basics

~20 s

Binary search needs only a monotone yes/no test over an ordered range of candidates, not a stored array. If feasible(x) is false below a threshold and true above it, halve that virtual boolean sequence to find the first true.

open as a page

How do lower bound and upper bound differ on a sorted array holding several copies of the target?

level: middleimportance: must knowfreq 66%

basics

~20 s

Lower bound returns the first index whose element is at least the target: the first copy. Upper bound returns the first strictly greater index: one past the last copy. Their difference is the occurrence count.

open as a page

In a leftmost-occurrence binary search, why does a match record the index and keep searching left?

level: middleimportance: must knowfreq 62%

basics

~20 s

A match proves the target exists there, but a smaller matching index can only lie strictly left. So the loop saves the hit as its best candidate, discards the midpoint and everything right of it, and continues.

open as a page

How many probes does binary search need worst case on a billion sorted entries, and on a trillion?

level: middleimportance: must knowfreq 66%

basics

~20 s

About 30 probes for a billion entries and about 40 for a trillion: the worst case is floor(log2 n) + 1. Multiplying the data by a thousand adds only ten probes, because log2(1000) is roughly 10.

open as a page

Why does a binary search loop that rounds mid down and then sets lo = mid hang on a two-element range?

level: middleimportance: must knowfreq 62%

basics

~20 s

Rounding down makes the midpoint equal the lower bound whenever two candidates remain, so assigning it back to the lower bound leaves the range unchanged and the loop repeats that state forever. Every branch must strictly shrink the range.

open as a page

Why does sort-then-binary-search lose to a single scan for one lookup in a large unsorted file?

level: middleimportance: must knowfreq 68%

basics

~20 s

Sorting costs O(n log n) before the O(log n) lookup, so the total is dominated by the sort and is strictly worse than one O(n) scan. Ordering only pays once its cost is amortized over enough later queries.

open as a page

In a row- and column-sorted grid, why does starting at the top-right corner discard a row or column?

level: middleimportance: must knowfreq 65%

basics

~20 s

The top-right cell is the largest in its row and smallest in its column, so one comparison rules out a whole line: too big drops the column, too small drops the row. That bounds the walk at m + n steps.

open as a page

In peak finding, when a[mid] < a[mid+1], why is discarding the entire left half safe?

level: middleimportance: must knowfreq 50%

basics

~20 s

The loop maintains an invariant, not an order: the surviving range always contains a peak. When a[mid] < a[mid+1] the readings rise, and a rising path inside a finite array must reach a local maximum before it runs out.

open as a page

How do you decide which half of a rotated sorted array is in order at each step?

level: middleimportance: must knowfreq 70%

basics

~20 s

Compare the midpoint value against a range endpoint, never against the target. If the midpoint value is at most the value at the high end, the segment from midpoint to high is in order; otherwise the low-to-midpoint segment is.

open as a page

How do you prove a feasibility predicate is monotone before binary searching an answer range?

level: seniorimportance: must knowfreq 56%

basics

~20 s

Prove it by argument, not by sampling: show that any solution meeting the constraint at one candidate still meets it when the candidate moves in the relaxing direction. Sampling can disprove monotonicity with a single counterexample, but never establish it.

open as a page

When binary searching for a minimum charging rate, what does the range hold and what does a midpoint test?

level: juniorimportance: should knowfreq 45%

basics

~20 s

Binary search on the answer searches the range of possible answers, because the input is not ordered by the quantity you want. Each midpoint is a candidate answer, tested by a feasibility check that returns only yes or no.

open as a page

How does exponential search find a search range on a sorted input of unknown size?

level: juniorimportance: should knowfreq 45%

basics

~20 s

It probes index 1, then 2, 4, 8 and so on until a probe reaches or passes the target or falls off the end, then binary searches only the interval between the previous probe and that one.

open as a page

How does interpolation search choose its next probe index, and what must the data satisfy?

level: juniorimportance: should knowfreq 30%

basics

~20 s

Interpolation search guesses the probe index by linearly interpolating the sought key between the two endpoint values, instead of always taking the midpoint. It needs sorted, randomly accessible keys you can do arithmetic on, and it only pays off when values are spaced near-uniformly.

open as a page

Why can't binary search find a unimodal cost curve's minimum, and what does ternary search do instead?

level: juniorimportance: should knowfreq 32%

basics

~20 s

Binary search needs a monotone test, and one probe on a fall-then-rise curve cannot say which side the minimum is on. Ternary search compares two interior probes to discard the outer third that provably cannot contain it.

open as a page

Why does a first-true binary search over an answer range set hi = mid instead of mid - 1?

level: middleimportance: should knowfreq 50%

basics

~20 s

A midpoint that tests feasible is itself a candidate answer. The loop's invariant is that the smallest feasible value lies inside lo..hi, so a true probe narrows hi to mid; mid - 1 would discard the proven value.

open as a page

Why does a half-open lower bound search assign hi = mid rather than hi = mid - 1?

level: middleimportance: should knowfreq 50%

basics

~20 s

Because mid may itself be the answer. A midpoint that satisfies the predicate is the earliest qualifying index found so far, so it must stay in range; mid - 1 discards it and the search returns a position too far left.

open as a page

In a collapsing rightmost-occurrence search, why does a floored midpoint with lo = mid loop forever?

level: middleimportance: should knowfreq 45%

basics

~20 s

A floored midpoint equals the low bound whenever two elements remain, so the branch that keeps the midpoint by assigning it back to the low bound makes no progress and the iteration repeats identically. Rounding the midpoint up fixes it.

open as a page

Why does binary search lose its O(log n) advantage on a sorted linked structure?

level: middleimportance: should knowfreq 50%

basics

~20 s

The halving argument counts comparisons but assumes reaching the midpoint is cheap. In a linked structure you must walk to the midpoint, and the walks sum to n/2 + n/4 + ... which is O(n), so total work is linear.

open as a page

In binary search, what changes when you use a half-open range [lo, hi) instead of a closed [lo, hi]?

level: middleimportance: should knowfreq 45%

basics

~20 s

Four things move together: the initial upper bound (one past the end versus the last index), the loop condition, which shrink step keeps the midpoint, and how an empty range is spelled. Never mix halves of the two conventions.

open as a page

showing 1–30 of 57