Description
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.
Constraints
- 1 <= bad <= n <= 231 - 1
Examples
- Example 1:
 Input:n = 5, bad = 4Output: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 = 1Output:1
Solution 1: Brute-Force
Steps
- The most intuitive and basic solution is to iterate from version 1to versionnsequentially and check one by one. IfisBadVersionreturnsTrue, then immediately returns the current version.
Codes
def first_bad_version(n: int) -> int:
    for version in range(1, n + 1):
        if isBadVersion(version):
            return versionComplexities
- Time Complexity: O(N), where N isn.
- Space Complexity: O(1)
Solution 2: Binary Search
Thought
According to the requirements of the problem, we need to find a specific target within a range ([1, 2, ..., n]) where the elements in the array are sorted. This gives us enough hints to use binary search. During each search, we continually narrow down the search range, getting closer to the target we are looking for.
Steps
- Use two pointers, leftandright, to represent the left and right boundaries of the current search range.
- When leftis less than or equal toright:- Calculate the midpoint midof the current range asmid = (left + right) // 2.
- Check the version pointed to by mid. If it is a normal version (isBadVersion(mid) == False), it means that all versions beforemidare also normal and can be skipped. Move theleftpointer to the element immediately aftermid.
- If midpoints to a bad version (isBadVersion(mid) == True), it’s important to note thatmidmay not be the answer we’re looking for because we want to find the first bad version. In this case, we need to check if the version beforemid(mid - 1) is also a bad version. If it is, it means thatmidis not the answer, so we move therightpointer to the element beforemidand repeat the above steps. On the other hand, if the version beforemidis a normal version, it implies thatmidis indeed the first bad version, so we can directly returnmid.
 
- Calculate the midpoint 
Codes
def first_bad_version(self, n: int) -> int:
        left = 1
        right = n
        
        while left <= right:
            mid = (left + right) // 2
            if not isBadVersion(mid):
                left = mid + 1
            else:
                if mid > 1 and isBadVersion(mid - 1):
                    right = mid - 1
                else:
                    return midComplexities
- Time Complexity: O(logN), where N isn.
- Space Complexity: O(1)
References
- LeetCode link: First Bad Version – LeetCode


