File: first-bad-version/solution.py

Date: 2026-06-06

Time: 16:50

first-bad-version/solution.py

Purpose

This file solves LeetCode 278 — First Bad Version. It finds the earliest bad version in a sequence [1, n] where versions transition from good to bad at some point and never go back. The function minimizes calls to the isBadVersion API — a constraint of the original problem.

Key Components

firstbadversion(n, isBadVersion) — The sole public function. It accepts the version count n and a predicate isBadVersion, and returns the smallest integer v in [1, n] where isBadVersion(v) is True.

The signature departs from LeetCode's class-based convention (where isBadVersion is inherited via VersionControl). Instead, it takes the predicate as a parameter via dependency injection, making it testable without subclassing.

Patterns

Left-biased binary search. The loop maintains the invariant that the answer is in [left, right]. When isBadVersion(mid) is true, the answer could be mid itself, so right = mid (not mid - 1). When false, mid is definitely not the answer, so left = mid + 1. The loop exits when left == right, which is the answer.

Overflow-safe midpoint. mid = left + (right - left) // 2 avoids integer overflow that (left + right) // 2 could cause in languages with fixed-width integers. In Python this is unnecessary (arbitrary-precision ints), but it's a good habit and matches the canonical binary search template.

Dependencies

Imports: typing.Callable — used only for the type annotation on isBadVersion.

Imported by: first-bad-version/test_solution.py directly. The "Imported By" list in the prompt is misleading — those hundreds of test files import from their *own* solution.py, not this one; LeetCode repos typically share no cross-problem imports.

Flow

1. Initialize left = 1, right = n.

2. Loop while left < right:

3. Return left (which equals right).

Each iteration halves the search space, so the function makes at most ceil(log2(n)) calls to isBadVersion.

Invariants

Error Handling

None. The function trusts its inputs — no validation of n >= 1, no check that isBadVersion is callable, and no handling of the "no bad version exists" edge case. This is appropriate for a LeetCode solution where constraints are guaranteed.

Topics to Explore

Beliefs