Efficiently Locate the First Bad Version of a Product with Binary Search
Problem Statement
You're given a function isBadVersion(version)
that returns whether a version is bad. You have a series of versions numbered from 1
to n
, and your task is to find the first bad version. Once a version is bad, all the following versions are also bad.
The goal is to minimize the number of API calls to isBadVersion(version)
.
Example 1:
Input: n = 5, bad = 4
Output: 4
Explanation:
isBadVersion(3)
-> falseisBadVersion(5)
-> trueisBadVersion(4)
-> true
Thus, the first bad version is version 4
.
Example 2:
Input: n = 1, bad = 1
Output: 1
Explanation: There is only one version, and it is bad, so the output is 1
.
Constraints:
1 <= bad <= n <= 2^31 - 1
The version numbers are ordered sequentially.
Understanding the Problem
Since the function isBadVersion(version)
provides us with the information about whether a version is bad, our task is to minimize API calls while finding the exact point where the versions turn bad.
Key Observations:
If a version is bad, all the versions after it will also be bad.
If a version is not bad, then all previous versions are also not bad.
We need to locate the first bad version, so the solution must find this "boundary" efficiently.
Optimal Approach: Binary Search
The binary search algorithm is ideal for this problem because we are essentially searching for a point in a sorted sequence where the property changes from false
(good) to true
(bad). With binary search, we can reduce the time complexity to O(log n)
.
Approach Breakdown:
Initialize Pointers: Start with two pointers,
left
andright
.left
starts at1
(first version), andright
starts atn
(last version).Binary Search Loop:
Compute the midpoint,
mid
, betweenleft
andright
.Call
isBadVersion(mid)
:If
mid
is bad, check if it is the first bad version by verifying whethermid-1
is not bad. If it is, returnmid
.Otherwise, move the
right
pointer tomid - 1
(since all versions aftermid
are bad).If
mid
is not bad, move theleft
pointer tomid + 1
(since all versions beforemid
are good).
Return Result: When the pointers converge, the first bad version is found.
Code Implementation in TypeScript:
// The isBadVersion API is provided, we simulate it here for understanding.
// function isBadVersion(version: number): boolean { /* ... */ }
var solution = function (isBadVersion: any) {
return function (n: number): number {
let left = 1;
let right = n;
while (left <= right) {
let mid = Math.floor(left + (right - left) / 2);
if (isBadVersion(mid)) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return left;
};
};
How It Works:
We initialize
left
to 1 andright
ton
, representing the range of versions.We compute the midpoint and check if it's bad using
isBadVersion(mid)
.If it's bad, we check if it's the first bad version. If so, we return the version number. If not, we adjust the search range to the left half by moving
right
.If it's not bad, we adjust the search range to the right half by moving
left
.
Time Complexity:
Time Complexity:
O(log n)
because we are using binary search to reduce the search space in half each time.Space Complexity:
O(1)
since we only use a few variables for our pointers and calculations.
Comment if I have committed any mistake. Let's connect on my socials. I am always open for new opportunities , if I am free :P
Subscribe to my newsletter
Read articles from Saurav Maheshwari directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by