PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep

Quick Overview

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.

  • Medium
  • OpenAI
  • Coding & Algorithms
  • Machine Learning Engineer

Find earliest supporting dependency version

Company: OpenAI

Role: Machine Learning Engineer

Category: Coding & Algorithms

Difficulty: Medium

Interview Round: Technical Screen

##### 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.

Quick Answer: 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.

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 API `isSupported(v)`: a version supports the feature **if and only if** it appears in `supported_versions`. This list is always a subset of `versions`. 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: 1. **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. 2. **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. 3. **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) <= 200000` - `versions` is sorted ascending, all versions are distinct, and `supported_versions` is a subset of `versions`. - 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 = []` → `None` - `versions = []`, `supported_versions = []` → `None`

Constraints

  • 0 <= len(versions) <= 200000
  • versions is sorted in ascending semantic-version order, all versions are distinct, and supported_versions is a subset of versions
  • The support pattern obeys the hierarchical guarantees described above: a first supporting major exists if support exists at all; 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

Input: (["103.003.01", "103.003.02", "103.004.01", "104.000.01", "104.001.01", "104.001.02", "105.000.01"], ["103.004.01", "104.001.02", "105.000.01"])

Expected Output: "103.004.01"

Explanation: Major 103 is the first major whose latest version supports the feature. Inside it, minor 004 is the first supporting minor, and its only listed patch is the answer.

Input: (["101.000.01", "101.001.01", "102.000.01", "102.000.02", "102.001.01", "103.000.01"], ["102.000.02", "102.001.01", "103.000.01"])

Expected Output: "102.000.02"

Explanation: No version in major 101 supports the feature. In major 102, the first supporting minor is 000, and within that minor the first supporting patch is 02.

Input: (["200.000.01"], ["200.000.01"])

Expected Output: "200.000.01"

Explanation: The only version is supported, so it is also the earliest supporting version.

Input: (["300.000.01", "300.000.02"], [])

Expected Output: None

Explanation: No version supports the feature, so the correct return value is None.

Input: ([], [])

Expected Output: None

Explanation: An empty version list contains no supporting version.

Solution

def solution(versions, supported_versions):
    if not versions:
        return None

    supported = set(supported_versions)

    major_order = []
    major_map = {}

    for v in versions:
        major_str, minor_str, _ = v.split('.')
        major = int(major_str)
        minor = int(minor_str)

        if major not in major_map:
            major_order.append(major)
            major_map[major] = {'latest': v, 'minor_order': [], 'minors': {}}

        major_info = major_map[major]
        major_info['latest'] = v

        if minor not in major_info['minors']:
            major_info['minor_order'].append(minor)
            major_info['minors'][minor] = {'latest': v, 'versions': []}

        minor_info = major_info['minors'][minor]
        minor_info['latest'] = v
        minor_info['versions'].append(v)

    def first_true(items, predicate):
        lo, hi = 0, len(items) - 1
        answer = None
        while lo <= hi:
            mid = (lo + hi) // 2
            item = items[mid]
            if predicate(item):
                answer = item
                hi = mid - 1
            else:
                lo = mid + 1
        return answer

    first_major = first_true(major_order, lambda major: major_map[major]['latest'] in supported)
    if first_major is None:
        return None

    major_info = major_map[first_major]
    first_minor = first_true(major_info['minor_order'], lambda minor: major_info['minors'][minor]['latest'] in supported)
    if first_minor is None:
        return None

    patch_versions = major_info['minors'][first_minor]['versions']
    lo, hi = 0, len(patch_versions) - 1
    answer = None

    while lo <= hi:
        mid = (lo + hi) // 2
        version = patch_versions[mid]
        if version in supported:
            answer = version
            hi = mid - 1
        else:
            lo = mid + 1

    return answer
Explanation
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 its `latest` listed version, its `minor_order`, and its minors. - each minor tracks its own `latest` version and the ordered `versions` list 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).

Hints

  1. You do not need to probe every version. The latest version inside a major tells you whether that major contains any supporting version.
  2. After finding the first supporting major, repeat the same idea for minors, then binary search patches inside the chosen minor.
Last updated: May 4, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,000+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Implement a Distributed Rate Limiter - OpenAI (medium)
  • Compute Plant Infection Time - OpenAI (medium)
  • Implement IP Address Arithmetic - OpenAI (hard)
  • Simulate Infection Spread on a Grid - OpenAI (hard)
  • Implement Social Follow Recommendations - OpenAI (medium)