Talentd
FleetCode
Make and follow sheets.Sign in

First Bad Version solution and explanation

EasyBinary SearchInteractive5 min read47.5% acceptanceUpdated 9 Apr 2026
First bad version | Leetcode #278Techdose · 4:44 · 55K viewsWatch on YouTube
9 more videos on this problem
  1. First bad version | Leetcode #278Techdose · 4:44 · 55K views
  2. LeetCode First Bad Version Solution Explained - JavaNick White · 3:30 · 32K views
  3. First Bad Version - Leetcode 278 - Binary Search (Python)Greg Hogg · 8:12 · 14K views
  4. LeetCode 278. First Bad Version - Interview Prep Ep 74Fisher Coder · 7:09 · 3K views
  5. First Bad Version - LeetCode 278 - Coding Interview QuestionsOne Code Man · 4:02 · 2K views
  6. FIRST BAD VERSION | LEETCODE 278 | PYTHON BINARY SEARCH SOLUTIONCracking FAANG · 8:35 · 2K views
  7. LeetCode Tutorial 278. First Bad VersionGoodTecher · 10:43 · 2K views
  8. LeetCode 278. First Bad Version | JSer - JavaScript & AlgorithmJSer · 7:29 · 1K views
  9. LeetCode 278: First Bad Version Solution Explained | Binary Search ApproachPrepflix · 9:29 · 734 views
  10. 278. First Bad Version || using C++ || Leetcode Problem || Binary search topicCogent Coder · 9:50 · 194 views

The problem

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 - 1

Approach overview

Problem Overview: You receive n product versions and an API isBadVersion(version). Once a version becomes bad, every version after it is also bad. The goal is to find the first bad version while minimizing API calls.

Approach 1: Linear Scan (O(n) time, O(1) space)

The most straightforward strategy is checking each version sequentially from 1 to n. Call isBadVersion(i) for every version until the API returns true. The first time it returns true is the answer. This works because versions before the first bad one are guaranteed to be good. The downside is efficiency: in the worst case you call the API n times, which becomes expensive for very large inputs.

Approach 2: Binary Search Optimization (O(log n) time, O(1) space)

The key observation is that the versions form a monotonic pattern: a sequence of good versions followed by bad ones. That structure makes the problem ideal for binary search. Start with a search range [1, n]. Check the middle version. If isBadVersion(mid) is true, the first bad version lies in the left half (including mid). Otherwise, it must be in the right half. Narrow the search range until left == right. That index is the first bad version. This approach drastically reduces API calls from O(n) to O(log n).

Approach 3: Recursive Binary Search Method (O(log n) time, O(log n) space)

This version applies the same binary search idea but uses recursion instead of a loop. Each recursive call splits the search range and evaluates isBadVersion(mid). If the mid version is bad, recurse into the left half; otherwise recurse into the right half. The logic mirrors divide-and-conquer patterns common in binary search and interactive API problems. The time complexity remains O(log n), but recursion adds a call stack cost of O(log n).

Recommended for interviews: Interviewers expect the binary search solution. The linear scan proves you understand the problem constraints, but it fails scalability requirements. Implementing the iterative binary search shows you recognize the monotonic property and can minimize expensive API calls—exactly the optimization interviewers look for in search problems.

Approach 1: Binary Search Optimization

This approach uses the concept of binary search to efficiently find the first bad version by minimizing the number of calls made to the given isBadVersion API. By leveraging binary search, we can reduce the problem set size by half with each iteration, therefore achieving O(log n) time complexity.

class Solution:
    def firstBadVersion(self, n: int) -> int:
        left, right = 1, n
        while left < right:
            mid = left + (right - left) // 2
            if isBadVersion(mid):
                right = mid
            else:
                left = mid + 1
        return left
public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        int left = 1, right = n;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (isBadVersion(mid)) right = mid;
            else left = mid + 1;
        }
        return left;
    }
}
#include <stdbool.h>

// Forward declaration of isBadVersion API.
bool isBadVersion(int version);

class Solution {
public:
    int firstBadVersion(int n) {
        int left = 1, right = n;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (isBadVersion(mid)) right = mid;
            else left = mid + 1;
        }
        return left;
    }
};
/**
 * Definition for isBadVersion()
 * 
 * @param {integer} version number
 * @return {boolean} whether the version is bad
 * isBadVersion = function(version) {
 *     ...
 * };
 */

/**
 * @param {function} isBadVersion()
 * @return {function}
 */
var solution = function(isBadVersion) {
    /**
     * @param {integer} n Total versions
     * @return {integer} The first bad version
     */
    return function(n) {
        let left = 1, right = n;
        while (left < right) {
            let mid = Math.floor(left + (right - left) / 2);
            if (isBadVersion(mid)) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return left;
    };
};
#include <stdbool.h>

// Forward declaration of isBadVersion API.
bool isBadVersion(int version);

int firstBadVersion(int n) {
    int left = 1, right = n;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (isBadVersion(mid)) right = mid;
        else left = mid + 1;
    }
    return left;
}
public class Solution : VersionControl {
    public int FirstBadVersion(int n) {
        int left = 1, right = n;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (IsBadVersion(mid)) right = mid;
            else left = mid + 1;
        }
        return left;
    }
}

The Python implementation adopts the same binary search approach. The function initializes the left and right pointers, then iteratively refines the search range based on the evaluation provided by isBadVersion. The first bad version is identified when left converges with right.

Complexity

Time Complexity: O(log n)
Space Complexity: O(1)

Try this approach in the editor

Approach 2: Recursive Binary Search Method

This approach explores a recursive implementation of the binary search technique to identify the first bad version. Employing recursion allows the continual division of the search problem into smaller subproblems until the solution is found.

class Solution:
    def binarySearch(self, left: int, right: int) -> int:
        if left < right:
            mid = left + (right - left) // 2
            if isBadVersion(mid):
                return self.binarySearch(left, mid)
            else:
                return self.binarySearch(mid + 1, right)
        return left

    def firstBadVersion(self, n: int) -> int:
        return self.binarySearch(1, n)
public class Solution extends VersionControl {
    private int binarySearch(int left, int right) {
        if (left < right) {
            int mid = left + (right - left) / 2;
            if (isBadVersion(mid)) return binarySearch(left, mid);
            else return binarySearch(mid + 1, right);
        }
        return left;
    }
    public int firstBadVersion(int n) {
        return binarySearch(1, n);
    }
}
#include <stdbool.h>

// Forward declaration of isBadVersion API.
bool isBadVersion(int version);

int binarySearch(int left, int right) {
    if (left < right) {
        int mid = left + (right - left) / 2;
        if (isBadVersion(mid)) return binarySearch(left, mid);
        else return binarySearch(mid + 1, right);
    }
    return left;
}

class Solution {
public:
    int firstBadVersion(int n) {
        return binarySearch(1, n);
    }
};
/**
 * Definition for isBadVersion()
 * 
 * @param {integer} version number
 * @return {boolean} whether the version is bad
 * isBadVersion = function(version) {
 *     ...
 * };
 */

/**
 * @param {function} isBadVersion()
 * @return {function}
 */
var solution = function(isBadVersion) {
    /**
     * @param {integer} n Total versions
     * @return {integer} The first bad version
     */
    function binarySearch(left, right) {
        if (left < right) {
            let mid = Math.floor(left + (right - left) / 2);
            if (isBadVersion(mid)) {
                return binarySearch(left, mid);
            } else {
                return binarySearch(mid + 1, right);
            }
        }
        return left;
    }
    return function(n) {
        return binarySearch(1, n);
    };
};
#include <stdbool.h>

// Forward declaration of isBadVersion API.
bool isBadVersion(int version);

int binarySearch(int left, int right) {
    if (left < right) {
        int mid = left + (right - left) / 2;
        if (isBadVersion(mid)) return binarySearch(left, mid);
        else return binarySearch(mid + 1, right);
    }
    return left;
}

int firstBadVersion(int n) {
    return binarySearch(1, n);
}
public class Solution : VersionControl {
    private int BinarySearch(int left, int right) {
        if (left < right) {
            int mid = left + (right - left) / 2;
            if (IsBadVersion(mid)) return BinarySearch(left, mid);
            else return BinarySearch(mid + 1, right);
        }
        return left;
    }

    public int FirstBadVersion(int n) {
        return BinarySearch(1, n);
    }
}

This Python solution embeds a binarySearch helper function to recursively zero in on the first bad version. Each call analyzes the status of the mid-point version, narrowing the searcher's focus until the exact location of the first bad version is discerned.

Complexity

Time Complexity: O(log n)
Space Complexity: O(log n) - due to recursion stack

Try this approach in the editor

Approach 3: Binary Search

We define the left boundary of the binary search as l = 1 and the right boundary as r = n.

While l < r, we calculate the middle position mid = \left\lfloor \frac{l + r}{2} \right\rfloor, then call the isBadVersion(mid) API. If it returns true, it means the first bad version is between [l, mid], so we set r = mid; otherwise, the first bad version is between [mid + 1, r], so we set l = mid + 1.

Finally, we return l.

The time complexity is O(log n), and the space complexity is O(1).

/**
 * 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;
    };
};
/**
 * 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
}
// 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
    }
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Binary Search Optimization

Time Complexity: O(log n)
Space Complexity: O(1)

Recursive Binary Search Method

Time Complexity: O(log n)
Space Complexity: O(log n) - due to recursion stack

Binary Search–

Complexity analysis

ApproachTimeSpaceWhen to Use
Linear ScanO(n)O(1)Simple baseline solution or when n is very small
Binary Search OptimizationO(log n)O(1)Optimal approach when versions follow a monotonic good→bad pattern
Recursive Binary SearchO(log n)O(log n)When recursion is preferred for divide-and-conquer clarity

Frequently asked questions

Is First Bad Version easy or hard?

First Bad Version is categorized as an Easy problem on LeetCode. The implementation is short, but it tests whether you recognize the monotonic pattern and apply binary search correctly to minimize API calls.

First Bad Version Python/Java solution

Both Python and Java implementations follow the same binary search pattern. Maintain left and right boundaries, check the middle version using isBadVersion, and shrink the search space accordingly. The final index where left equals right is the first bad version with O(log n) time complexity.

How to solve First Bad Version in O(log n)?

Use binary search on the version range from 1 to n. Compute mid and call isBadVersion(mid). If mid is bad, move the right boundary to mid; otherwise move the left boundary to mid + 1. Continue until both pointers meet, which identifies the first bad version in O(log n) time.

What is the best approach for First Bad Version?

Binary search is the optimal approach because versions form a monotonic sequence: all good versions come before bad ones. By repeatedly halving the search range, you find the first bad version in O(log n) time while using only O(1) space. This also minimizes expensive API calls to isBadVersion.

Is First Bad Version asked at Google/Amazon/Meta?

First Bad Version is a classic binary search interview question and has appeared in coding interviews at companies like Google and Amazon. It tests recognition of monotonic conditions and efficient search using minimal API calls.

What data structure is used in First Bad Version?

No special data structure is required. The solution relies on the binary search algorithm over an implicit sorted range of version numbers. The monotonic property (good versions followed by bad versions) enables efficient searching.

What is the time complexity of First Bad Version?

The optimal binary search solution runs in O(log n) time because the search range is halved on every step. A naive linear scan would take O(n) time since it may check every version sequentially. Space complexity is O(1) for the iterative solution.

Comments

Now write it yourselfClose this page and solve First Bad Version in the editor, without looking.
Practise First Bad Version