Imagine you have a row of boxes. Each box has a number inside it. You don’t know the numbers, but you’re told the boxes are sorted in increasing order.
Now, you want to find whether a specific number x exists inside one of these boxes.
1. The Naive Way
Your first thought: “Let me open each box from left to right and check.”
That works, but in the worst case you’ll open all n boxes → O(n).
2. The Smarter Way
What if you could ignore half of the boxes at once?
How? By always checking the middle box:
- If
a[mid] == x→ found it. - If
a[mid] > x→ you can safely ignore the right half (since everything there is larger). - If
a[mid] < x→ ignore the left half.
Then, repeat the process on the remaining half.
This halves the range every step:
100 → 50 → 25 → 12 → 6 → 3 → 1
So in the worst case, you only open about log2(n) boxes.
That’s why binary search runs in O(log n).
3. Why Choose the Middle?
If you pick a random element (not the middle), you can’t guarantee you’ll eliminate a large part of the search space. The middle is optimal because it ensures we cut the range almost evenly each time.
4. Understanding Logarithm
log_x(y) = “How many times do I divide y by x until it becomes 1?”
For binary search, base = 2. So, log2(100) ≈ 7 → at most 7 steps to search among 100 elements.
5. C++ Implementation
// Standard Binary Search
int solve(vector<int>& a, int x) {
int l = 0, r = (int)a.size() - 1;
while (l <= r) {
int md = (l + r) / 2;
if (a[md] == x) return md; // found
else if (a[md] < x) l = md + 1;
else r = md - 1;
}
return -1; // not found
}
6. Binary Search on Answer (Important!)
Binary search isn’t only for searching in arrays. We often apply it when:
- We have many candidate answers.
- They follow a monotonic property (all bad → all good, or all good → all bad).
Examples:
1 1 1 1 1 0 0 0 → find the last "1"
0 0 0 0 0 1 1 1 → find the first "1"
We don’t search for a specific number, we search for the best candidate.
7. Upper Bound & Lower Bound
lower_bound(a.begin(), a.end(), x)→ first index witha[i] >= x.upper_bound(a.begin(), a.end(), x)→ first index witha[i] > x.
Implementation of upper_bound:
int upper_bound(vector<int>& a, int x) {
int l = 0, r = (int)a.size() - 1;
int res = -1;
while (l <= r) {
int md = (l + r) / 2;
if (a[md] > x) {
res = md; // candidate answer
r = md - 1; // try smaller index
} else {
l = md + 1;
}
}
return res;
}
8. When to Use Binary Search?
Whenever:
- You want the smallest or largest element satisfying a condition.
- You have a monotonic function (true/false transition).
9. Practice Problems
Key Takeaways
- Binary search = cut search space in half each step.
- Runs in O(log n).
- Works on sorted arrays or monotonic answers.
- Super useful for answer searching, not only for array elements.
If the array is sorted, use binary search → O(log n). If the array is not sorted, don’t sort it just to apply binary search → instead use linear search → O(n), which is more efficient.









I don't know why someone downvote.
This is a good article about basic knowledges of binary search.
Don't vote without content but only rating.
Idiots will downvote every blog, which written by low rate users
I wrote a blog about Segment Trees and got downvoted so hard :( . I spent 3 hours on that! I also made a blog about some problems I made, that, I spent more than a MONTH making it
I read the post, it is nice for beginner but there is a little imprecision.
Where you say that there are 2 cases in which binary search is useful, you mention a monotonic function but that is the requirement for the usual binary search, that lets you, for instance, find the index of an element belonging to a sorted array.
Maybe the second case that you wanted to list is the following:
Moreover, I suggest you to use LaTeX for mathematical notation.
i.e.
O(log n) $$$\to$$$ $$$\mathcal{O}(\log{n})$$$
log2(100) $$$\to$$$ $$$\log_2{(100)}$$$
people here are so toxic..hate every low rated users