Binary Search is quite easy to understand conceptually. Basically, it splits the search space into two halves and only keep the half that probably has the search target and throw away the other half that would not possibly have the answer. In this manner, we reduce the search space to half the size at every step, until we find the target. Binary Search helps us reduce the search time from linear O(n) to logarithmic O(log n). But when it comes to implementation, it’s rather difficult to write a bug-free code in just a few minutes. Some of the most common problems include:
left < right
or left <= right
as the while loop condition?left
and right
?left = mid
, left = mid + 1
and right = mid
, right = mid — 1
?A rather common misunderstanding of binary search is that people often think this technique could only be used in simple scenario like “Given a sorted array, find a specific value in it”. As a matter of fact, it can be applied to much more complicated situations.
After a lot of practice in LeetCode, I’ve made a powerful binary search template and solved many Hard problems by just slightly twisting this template. I’ll share the template with you guys in this post. **I don’t want to just show off the code and leave. Most importantly, I want to share the logical thinking: how to apply this general template to all sorts of problems. **Hopefully, after reading this post, people wouldn’t be pissed off any more when LeetCoding, “Holy sh*t! This problem could be solved with binary search! Why didn’t I think of that before!”
Suppose we have a search space. It could be an array, a range, etc. Usually it’s sorted in ascend order. For most tasks, we can transform the requirement into the following generalized form:
Minimize k , s.t. condition(k) is True
The following code is the most generalized binary search template:
What’s really nice of this template is that, for most of the binary search problems, we only need to modify three parts after copy-pasting this template, and never need to worry about corner cases and bugs in code any more:
left
and right
. Only one rule: set up the boundary to include all possible elements;return left
or return left — 1
? Remember this: after exiting the while loop, **left**
is the minimal k satisfying the **condition**
function;condition
function. This is the most difficult and most beautiful part. Needs lots of practice.Below I will show you guys how to apply this powerful template to many LeetCode problems.
First, we initialize left = 1
and right = n
to include all possible values. Then we notice that we don’t even need to design the condition
function. It’s already given by the isBadVersion
API. Finding the first bad version is equivalent to finding the minimal k satisfying isBadVersion(k) is True
. Our template can fit in very nicely:
Quite an easy problem. We need to search for maximal k satisfying k^2 <= x
, so we can easily come up with the solution:
There’s one thing I’d like to point out. Remember I say that we usually look for the minimal k value satisfying certain condition? But in this problem we are searching for maximal k value instead. Feeling confused? Don’t be. Actually, the maximal k satisfying isBadVersion(k) is False
is just equal to the minimal k satisfying isBadVersion(k) is True
minus one. This is why I mentioned earlier that we need to decide which value to return, left
or left — 1
.
#algorithms #leetcode #binary-search #algorithms