Coding questions · OpenAI
Find earliest supporting dependency version
This question evaluates a candidate's ability to design efficient search algorithms and reason about algorithmic complexity under constraints such as non-monotonic predicate behavior and a rate-limited black-box API.
Question
Given a list of dependency versions (e.g. [103.003.02, 103.003.03, 203.003.02]) and a black-box API isSupported(v), design an algorithm to find the earliest (lowest) version that supports a target feature. 2) Versions follow {major}.{minor}.{patch}. Support is not monotonic: a higher version may drop support, but it is guaranteed that some later version will support again. The API is rate-limited, so total calls must be sub-linear to the number of versions. Devise a strategy—e.g., group by latest patch per major, binary-search majors, then minors, then patches—to minimize API usage while reliably returning the earliest supporting version.
Find Earliest Supporting Dependency Version
Find the earliest dependency version that supports a target feature, using as few API probes as possible.
What to implement
solution(versions, supported_versions)
versions— a list of distinct version strings, each in the form"major.minor.patch"(numeric components, possibly zero-padded, e.g."104.000.01"). The list is already sorted in ascending semantic-version order.supported_versions— a list that simulates a black-box APIisSupported(v): a version supports the feature if and only if it appears insupported_versions. This list is always a subset ofversions.
Return the earliest (smallest in the sorted order) version string that supports the feature, or None if no version supports it.
Why this isn't a plain search
Support is not monotonic across the full version list: an early version may support the feature, a later version (in a new major or minor) may not, and an even later one may support again. So you cannot simply scan or binary-search the whole list directly.
Structure guarantees (these make a sub-linear API strategy possible)
The data obeys a three-level hierarchical pattern:
- Major level. If any version supports the feature, there is a first supporting major, and every major after it also contains at least one supporting version.
- Minor level. Inside that first supporting major, there is a first supporting minor, and every later minor within that major also contains at least one supporting version.
- Patch level. Inside that first supporting major/minor pair, support is monotonic by patch among the listed versions — once support starts, it continues.
Additionally, if a major or a minor contains any supporting version, then its latest listed version is guaranteed to be supporting. This lets you probe a single representative version per major and per minor.
The earliest supporting version is therefore the first supporting patch inside the first supporting minor inside the first supporting major.
Constraints
0 <= len(versions) <= 200000versionsis sorted ascending, all versions are distinct, andsupported_versionsis a subset ofversions.- The support pattern always obeys the hierarchical guarantees above: if support exists at all, a first supporting major exists; within it a first supporting minor exists; within it a first supporting patch exists; and the latest listed version of any supporting major or minor is also supporting.
Examples
versions = ["103.003.01", "103.003.02", "103.004.01", "104.000.01", "104.001.01", "104.001.02", "105.000.01"],supported_versions = ["103.004.01", "104.001.02", "105.000.01"]→"103.004.01"versions = ["101.000.01", "101.001.01", "102.000.01", "102.000.02", "102.001.01", "103.000.01"],supported_versions = ["102.000.02", "102.001.01", "103.000.01"]→"102.000.02"versions = ["200.000.01"],supported_versions = ["200.000.01"]→"200.000.01"versions = ["300.000.01", "300.000.02"],supported_versions = []→Noneversions = [],supported_versions = []→None
Hints
- You do not need to probe every version. The latest version inside a major tells you whether that major contains any supporting version.
- After finding the first supporting major, repeat the same idea for minors, then binary search patches inside the chosen minor.
Approach
The data hides a feature behind three nested layers, and within each layer the supporting versions form a suffix (once support starts, it never stops). So the solution does three binary searches, one per layer.
Step 1 — bucket the versions. A single linear pass splits every "major.minor.patch" string and groups versions into a nested map:
major_order/major_map[major]— ordered list of distinct majors, each tracking itslatestlisted version, itsminor_order, and its minors.- each minor tracks its own
latestversion and the orderedversionslist for its patches.
Because input is already sorted, latest ends up holding the highest version seen in each bucket.
Step 2 — find the first supporting major. first_true is a classic "leftmost true" binary search. The key guarantee: if a major contains any supporting version, its latest listed version is supporting, and supporting majors form a suffix. So testing major_map[major]['latest'] in supported is monotonic across major_order, and the binary search finds the earliest qualifying major.
Step 3 — find the first supporting minor inside that major using the same latest in supported predicate over minor_order.
Step 4 — find the first supporting patch. Within the chosen major/minor, support is monotonic by patch, so a plain leftmost binary search over patch_versions returns the earliest supported version.
If any layer has no supporting bucket, the search returns None. The empty-input and all-None cases short-circuit correctly. Correctness rests entirely on the problem's suffix/monotonicity guarantees, which make each in supported probe a valid binary-search predicate.
- Time complexity: O(n)
- Space complexity: O(n)