We have a linear sequence of versions numbered 1 through n. At some point a version goes bad, and every version after it is also bad. So the sequence looks like [good, good, ..., good, bad, bad, ..., bad]. We need to find the boundary: the first version where it flips from good to bad.
We can only determine whether a version is bad by calling the isBadVersion API, and we want to minimize the number of calls. This is a search problem on a monotonic structure. All good versions come before all bad versions, so there is a single partition point to locate.
1 <= bad <= n <= 2^31 - 1, so n can be up to about 2.1 billion. A linear scan would make up to 2.1 billion API calls, which is too slow. The solution must be logarithmic.1 <= bad guarantees at least one bad version, so we never have to handle the case where no bad version exists.(low + high) / 2 adds two values that can each approach 2^31 - 1, and their sum overflows a signed 32-bit integer. The approaches below compute the midpoint as low + (high - low) / 2 to stay within range.Start from version 1 and check each version in order. The first version where isBadVersion returns true is the answer. Test version 1; if it is good, move to version 2, and continue until the first bad version appears. The approach is correct but ignores the monotonic structure: each call rules out only the single version it tested.
i from 1 to n, call isBadVersion(i).i where isBadVersion(i) returns true.isBadVersion n times.Each API call eliminates only a single version. Because the versions are partitioned into a good block followed by a bad block, we can eliminate half the remaining range with each call instead.
The versions form a monotonic sequence: all good versions come first, then all bad versions. That monotonicity is what binary search needs. Instead of checking versions one at a time, we check the middle version and discard half the range based on the result.
If the middle version is bad, the first bad version is at the middle or before it. If the middle version is good, the first bad version is after the middle. Either way, the search range halves with each API call, so for n = 2^31 - 1 the count drops from about 2 billion to at most 31, since log2(2^31) = 31.
The loop maintains one invariant: the first bad version always lies within [low, high]. When mid is bad, we set high = mid rather than mid - 1 because mid itself might be the first bad version, and dropping it could discard the answer. When mid is good, every version up to and including mid is good, so we set low = mid + 1. Each step shrinks the range while keeping the answer inside it, and the range never becomes empty because mid is strictly less than high whenever low < high. When low == high the range holds exactly one version, which is the first bad one.
low = 1 and high = n.low < high:mid = low + (high - low) / 2 (to avoid integer overflow).isBadVersion(mid) is true, set high = mid (the first bad version is at mid or earlier).isBadVersion(mid) is false, set low = mid + 1 (the first bad version is after mid).low == high, return low. This is the first bad version.low, high, and mid.Binary search always searches the full range [1, n], so it costs about log2(n) calls regardless of where the first bad version sits. When the first bad version is near the start, we can do fewer calls by finding a tight upper bound before searching.
If the first bad version is small (say version 3 out of a billion), binary search still starts at the midpoint near 500 million and spends several calls walking back down. We can instead expand a bound from the left: check version 1, then 2, then 4, 8, 16, and so on, doubling each time until a call returns bad. Once a bad version is found at bound, the first bad version lies between the previous bound and bound, and we binary search that narrow window.
The doubling phase takes about log2(p) calls to bracket the first bad version at position p, and the binary search over the bracketed window takes another log2(p) calls, since the window has size at most p. The total is O(log p), which beats O(log n) whenever the first bad version is far from the end.
bound = 1.bound < n and isBadVersion(bound) is false, double bound (capping it at n).[bound / 2 + 1, bound]: everything at bound / 2 and below was good, and bound is bad (or equals n). Set low = bound / 2 + 1 and high = min(bound, n).low < high, compute mid = low + (high - low) / 2, set high = mid if mid is bad, else low = mid + 1.low.bound, low, high, and mid.For this problem the input range [1, n] is fully known up front, so plain binary search (Approach 2) is the standard choice and its 31-call worst case is already small. Exponential search matters when the upper bound is unknown or unbounded, such as searching a stream or an infinite sorted sequence, where you cannot start binary search without first bracketing the target.