Boundary update without `+1` / `-1`
Wrong move: Setting `lo = mid` or `hi = mid` can stall and create an infinite loop.
Usually fails on: Two-element ranges never converge.
Fix: Use `lo = mid + 1` or `hi = mid - 1` where appropriate.
Build confidence with an intuition-first walkthrough focused on binary search fundamentals.
You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad.
Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one, which causes all the following ones to be bad.
You are given an API bool isBadVersion(version) which returns whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.
Example 1:
Input: n = 5, bad = 4 Output: 4 Explanation: call isBadVersion(3) -> false call isBadVersion(5) -> true call isBadVersion(4) -> true Then 4 is the first bad version.
Example 2:
Input: n = 1, bad = 1 Output: 1
Constraints:
1 <= bad <= n <= 231 - 1Problem summary: You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad. Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one, which causes all the following ones to be bad. You are given an API bool isBadVersion(version) which returns whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Binary Search
5 4
1 1
find-first-and-last-position-of-element-in-sorted-array)search-insert-position)guess-number-higher-or-lower)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #278: First Bad Version
/* The isBadVersion API is defined in the parent class VersionControl.
boolean isBadVersion(int version); */
public class Solution extends VersionControl {
public int firstBadVersion(int n) {
int l = 1, r = n;
while (l < r) {
int mid = (l + r) >>> 1;
if (isBadVersion(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
}
}
// Accepted solution for LeetCode #278: First Bad Version
/**
* Forward declaration of isBadVersion API.
* @param version your guess about first bad version
* @return true if current version is bad
* false if current version is good
* func isBadVersion(version int) bool;
*/
func firstBadVersion(n int) int {
l, r := 1, n
for l < r {
mid := (l + r) >> 1
if isBadVersion(mid) {
r = mid
} else {
l = mid + 1
}
}
return l
}
# Accepted solution for LeetCode #278: First Bad Version
# The isBadVersion API is already defined for you.
# def isBadVersion(version: int) -> bool:
class Solution:
def firstBadVersion(self, n: int) -> int:
l, r = 1, n
while l < r:
mid = (l + r) >> 1
if isBadVersion(mid):
r = mid
else:
l = mid + 1
return l
// Accepted solution for LeetCode #278: First Bad Version
// The API isBadVersion is defined for you.
// isBadVersion(version:i32)-> bool;
// to call it use self.isBadVersion(version)
impl Solution {
pub fn first_bad_version(&self, n: i32) -> i32 {
let (mut l, mut r) = (1, n);
while l < r {
let mid = l + (r - l) / 2;
if self.isBadVersion(mid) {
r = mid;
} else {
l = mid + 1;
}
}
l
}
}
// Accepted solution for LeetCode #278: First Bad Version
/**
* The knows API is defined in the parent class Relation.
* isBadVersion(version: number): boolean {
* ...
* };
*/
var solution = function (isBadVersion: any) {
return function (n: number): number {
let [l, r] = [1, n];
while (l < r) {
const mid = (l + r) >>> 1;
if (isBadVersion(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
};
};
Use this to step through a reusable interview workflow for this problem.
Check every element from left to right until we find the target or exhaust the array. Each comparison is O(1), and we may visit all n elements, giving O(n). No extra space needed.
Each comparison eliminates half the remaining search space. After k comparisons, the space is n/2ᵏ. We stop when the space is 1, so k = log₂ n. No extra memory needed — just two pointers (lo, hi).
Review these before coding to avoid predictable interview regressions.
Wrong move: Setting `lo = mid` or `hi = mid` can stall and create an infinite loop.
Usually fails on: Two-element ranges never converge.
Fix: Use `lo = mid + 1` or `hi = mid - 1` where appropriate.