SWE II · HackerRank OA Coding

Microsoft OA 选 K 台不相邻服务器:最小化选中最大值

二分服务器值上限,线性贪心判定能否挑出 k 个互不相邻的位置;推导单调性、复杂度与非法 k 边界。

题目重点:二分服务器值上限,线性贪心判定能否挑出 k 个互不相邻的位置;推导单调性、复杂度与非法 k 边界。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 位置按输入数组线性排列,不是首尾相邻的环。
  • 必须恰好选 k 台;若可选至少 k 台,则任选其中 k 台也满足上限。
  • k=0 的最大值无数学定义,训练代码拒绝;k>(n+1)//2 不可能,亦拒绝。
  • 服务器值可以为负;二分范围取实际最小/最大值。

解题路线

  1. 给定阈值 x,只允许选 values[i]≤x 的位置。问题变成判断能否挑至少 k 个不相邻下标。
  2. 从左到右一旦遇到可选位置就立即选择,并跳过下一位置;在一条线性序列中,这个最早选择不会减少之后可选的数量,可用交换论证把任意最优解的首个选择左移。
  3. 若阈值 x 可行,则所有更大阈值也可行;对 [min(values),max(values)] 二分最小可行 x。
  4. 返回找到的 x。若还要输出具体 k 台,在该阈值下重跑贪心,选够 k 后停止。

手动走一遍

[2,3,5,9]、k=2:阈值 3 时能选 2 或 3,但不能两者都选,故不可行;阈值 5 时选下标 0 的 2,再选下标 2 的 5,最大值 5。阈值更高仍可行,二分下界停在 5。

Python 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

from collections.abc import Sequence


def minimum_maximum_server_value(values: Sequence[int], k: int) -> int:
    """Choose exactly k nonadjacent positions, minimizing their maximum value."""
    n = len(values)
    if k < 0 or k > (n + 1) // 2:
        raise ValueError("invalid k")
    if k == 0:
        raise ValueError("maximum of an empty selection is undefined")

    def feasible(limit: int) -> bool:
        picked = 0
        i = 0
        while i < n:
            if values[i] <= limit:
                picked += 1
                if picked >= k:
                    return True
                i += 2
            else:
                i += 1
        return False

    lo, hi = min(values), max(values)
    while lo < hi:
        mid = lo + (hi - lo) // 2
        if feasible(mid):
            hi = mid
        else:
            lo = mid + 1
    return lo


if __name__ == "__main__":
    assert minimum_maximum_server_value([2, 3, 5, 9], 2) == 5

复杂度

每次判定 O(n),二分约 O(log R) 次,R=maxValue−minValue+1,故 O(n log R) 时间和 O(1) 额外空间。若值域巨大但不同值少,可先排序去重候选阈值,代价 O(n log n) 预处理。

易错点与追问

容易失分的边界

  • 排序服务器数组后挑最小 k 个会破坏原始相邻关系。
  • 贪心选中后忘记跳过下一位置。
  • 二分的判定写成‘恰好 k’并在找到 >k 个时误判失败。
  • 把环形相邻规则套到线性数组,导致首尾被错误视为冲突。
  • 没有处理 n=0、k=0 与 k 过大的接口契约。

继续深挖

  • 若服务器排成环,如何分首台选/不选两种情形?
  • 若最少间隔为 d>1,贪心跳过长度如何变化?
  • 如果最大值相同,如何输出字典序最小的下标集合?
✓已复制微信号!