Hello, and welcome to a course about binary search as a reasoning tool, not merely a familiar loop over a sorted vector. Over the course, you will move from precise boundary contracts and correctness arguments to answer-space searches, feasibility checks, implicit domains, and harder competitive-programming patterns.
The central shift begins here: binary search does not fundamentally search for a value. It finds a boundary in an ordered set of candidates. To use it reliably, first turn the problem into a yes/no question whose answers change in only one direction.
By the end of this lesson, you should be able to take a boundary-finding task, state its ordered search domain, define a Boolean predicate over that domain, and express the desired result as the first or last point at which that predicate holds.
From “find an element” to “find a transition”
Consider a sorted vector:
Suppose the task is:
Find the first index whose value is at least .
A direct description is “find the first .” But that wording is too narrow: if did not occur, the meaningful answer would still be the index where could be inserted while preserving sorted order.
Instead, define a predicate over indices:
Evaluating it at every index gives:
| Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 1 | 3 | 3 | 5 | 8 | 8 | 12 | |
| F | F | F | F | T | T | T |
The actual problem is now:
Find the first true position.
That boundary is index . The target value happens to occur there, but the predicate formulation also works when it does not.
For target , the same predicate,
produces:
The first true index is again , which is precisely the insertion position of .
This is the abstraction to keep:
- Identify a set of candidate answers.
- Put those candidates in an order.
- Ask one yes/no question about each candidate.
- Find the point at which answers switch from one truth value to the other.
The binary-search loop comes after this modeling work.
The required shape: monotonicity
For the canonical “first true” formulation, predicate values must have this shape:
Formally, if the ordered domain is , the predicate must be monotone nondecreasing:
Equivalently:
A true answer certifies every later candidate as true; a false answer certifies every earlier candidate as false. Those are exactly the facts that let binary search discard half the domain safely.

There are two usable orientations:
| Desired boundary | Predicate pattern | Typical statement |
|---|---|---|
| First true | First index with | |
| Last true | Last index with |
The two are not fundamentally different. If has the true-then-false pattern, then its complement
has the false-then-true pattern. You can then search for the first true of , which lies immediately after the last true of .
For now, make first true your default mental model. It is especially natural for minimums, insertion positions, and “at least” constraints.
Binary Search tutorial (C++ and Python)
Watch “Binary Search tutorial (C++ and Python)” by Errichto Algorithms for the visual shift from ordinary lookup to a false/true boundary. The examples emphasize why a qualifying midpoint is not automatically the final answer.
First watch lower bound. Focus on the change from “does this equal the target?” to “does this satisfy the condition?”, and why a true result means a smaller valid index may still exist. Then watch boundary viewpoint. In particular, follow the false-prefix/true-suffix interpretation, including the all-false and all-true cases. The rotated-array details are only a preview; the important idea today is designing a predicate whose truth values form one transition.
State the domain before defining the predicate
A predicate alone is not enough. It must be defined over an ordered domain of candidate answers.
In the sorted-vector example:
- Domain: indices
- Order: ordinary increasing index order
- Predicate:
- Boundary sought: first for which is true
This four-part statement is a compact problem specification. It also stops a common error: using a predicate over the wrong thing.
Example: threshold in a sorted vector
Task:
Find the first value at least
target.
Correct formulation:
Find the first true index.
Why is it monotone? Because is sorted. If , every later value is at least , hence also at least target.
Example: first element strictly greater than a target
Task:
Find the first element greater than
target.
Only the predicate changes:
This is still false followed by true. For
the values of are:
The first true is index . This is the conceptual meaning of upper_bound.
Example: last element at most a target
Task:
Find the last index satisfying .
The direct predicate is:
Its shape is:
That is a valid one-transition pattern, but it is the reverse orientation. A first-true equivalent is:
Find the first true index ; then the last index at most the target is .
This “find the first violation, then step back” transformation will be useful throughout the course.
Exact search is often a boundary problem in disguise
A conventional exact-match predicate looks like this:
For a sorted vector with duplicates, its truth values may look like:
That is not monotone: it changes from false to true and then back to false. A boundary search cannot safely use directly.
The repair is to search for a monotone threshold predicate instead:
Find its first true index . Then perform one final validation:
- If and , then is the first occurrence.
- Otherwise, the target is absent.
So even an “exact search” can be decomposed into:
- Find the lower boundary.
- Check whether the boundary element equals the target.
This is more general than returning immediately on equality, because it handles duplicates and naturally yields an insertion position when the target is absent.
Binary Search - Competitive Programming Tutorials
Read Topcoder’s explanation of predicates and its lower-bound conversion. It provides a concise formal test for whether your yes/no question has the one-directional structure binary search needs.
Begin with “Taking it further: the main theorem.” Read the predicate model, concentrating on the meaning of a candidate solution, an ordered search space, and the implication from one true result to all later true results. Continue through the next discussion of predicate design, especially decision reduction. The traveling-salesman example is illustrative rather than a binary-search recipe: the key requirement is that the yes/no predicate must also be efficiently evaluable. Finally, in the lower-bound example, read the conversion. Follow how “first element at least target” becomes a predicate over indices rather than an equality search.
Boundary contracts and the edge cases
For a finite index domain , define the boundary as:
when a true index exists.
But a robust contract must say what happens when no true index exists. The cleanest mathematical convention is to allow the boundary to be one past the vector:
with:
- if every position is true;
- if every position is false;
- otherwise, is the first true index.
For a sorted vector and
this gives the full insertion-position contract:
| Situation | Predicate pattern | Boundary |
|---|---|---|
| Target is no larger than every element | all true | |
| Target belongs between existing values | false then true | first qualifying index |
| Target is larger than every element | all false | |
| Vector is empty | no positions |
Notice that “all false” is not a failure of the method. It represents a legitimate boundary after the domain. Likewise, “all true” places the boundary before or at the first element.
At this stage, do not worry about which C++ loop variables represent this contract. The next lessons will derive half-open and sentinel-based implementations precisely. What matters today is that the problem contract is settled before any updates or midpoint calculations are written.
Beyond arrays: candidates can be possible answers
The domain does not need to be array indices. It can be any ordered collection of candidates.
Suppose a problem asks:
What is the minimum integer capacity that lets a set of packages be shipped within days?
The candidate answers are capacities, perhaps from the heaviest package weight up to the sum of all weights. Define:
We seek the first true capacity.
Why is monotone? If capacity is sufficient, every capacity larger than is also sufficient: extra capacity cannot make a feasible schedule infeasible.
This is a reduction from an optimization problem to a decision problem:
| Original wording | Predicate wording |
|---|---|
| Minimize the capacity | Is capacity sufficient? |
| Maximize an achievable score | Is score achievable? |
| Find the earliest acceptable day | Is day late enough? |
The question “is this candidate sufficient?” is frequently easier to answer than “what is the optimum?” Once its answers are monotone, the optimum is a boundary.
A useful discipline is to write the predicate as a complete English sentence before turning it into code. For example:
“There exists a schedule that finishes all jobs by time .”
That sentence makes the direction of monotonicity visible: increasing relaxes the deadline, so a true result remains true.
A predicate-design checklist
Before implementing any binary search, write down these five lines on paper or in a code comment:
- Candidate domain: What values could the answer be?
- Order: In what increasing order are candidates arranged?
- Predicate: What exactly does mean?
- Boundary: Do I seek the first true or the last true?
- Monotonicity proof: Why can the predicate change at most once?
For a lower bound, that becomes:
Domain: indices through .
Order: increasing index.
Predicate: means .
Boundary: first true, with if none exists.
Proof: sortedness means every later array value is at least as large.
For a minimum feasible capacity problem:
Domain: feasible integer capacity range.
Order: increasing capacity.
Predicate: means all work can be completed with capacity .
Boundary: first true.
Proof: a larger capacity only relaxes constraints.
If you cannot write a convincing monotonicity sentence, do not start coding binary search. Either the predicate is wrong, the domain order is wrong, or the problem needs another technique.
Key takeaways
Binary search is best understood as a search for a transition in a Boolean predicate over an ordered domain.
- A canonical first-true predicate has the form .
- The domain may be indices, times, capacities, scores, or another ordered set of candidate answers.
- Equality is often non-monotone; replace it with a threshold predicate such as , then validate the resulting boundary if exact presence matters.
- A complete formulation states the domain, predicate, boundary, edge-case behavior, and a short monotonicity argument.
- All-true and all-false predicate values are normal cases, not exceptional failures.
Next, you will focus on recognizing whether a proposed predicate is genuinely monotone—and on repairing tempting predicates that are not.
Can't find a good explanation? Sign up and we'll make it for you
Sign up