Azure Infrastructure · HM Coding

Microsoft 0..32000 无重复整数排序:Bitmap 与流式文件接口

输入未排序、数值唯一且落在 0..32000,用 4,001 字节位图标记,再按值域扫描输出有序文件。

题目重点:输入未排序、数值唯一且落在 0..32000,用 4,001 字节位图标记,再按值域扫描输出有序文件。

题意与假设

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

  • 值域两个端点均包含;输入每个整数最多一次,遇越界值训练代码报错。
  • 训练版 getNum() 用 None 表示 EOF,putNum(value) 写一个结果;题目 helper 的精确签名未给。
  • 仅需升序输出,不需保持输入顺序;内存足够容纳 32001 bits。

解题路线

  1. 分配 ceil(32001/8)=4001 个字节。读一个整数 v,就把 bits[v>>3] 的第 (v&7) 位设为 1。
  2. 输入结束后从 0 扫到 32000,凡位为 1 就调用 putNum(v)。输入无重复,因此每个 set bit 对应一个输出。
  3. 若输入确有重复而题目仍需保留多重性,位图会丢次数,必须改频次数组或外部排序;题目明确‘无重复’,无需擅自添加多重集语义。
  4. putNum 写文件失败时不能静默丢数,工程版应先写临时文件、校验输出计数后原子替换目标。

手动走一遍

输入顺序 [32000,0,8],分别置位,扫描值域时依次输出 0、8、32000。32000 的字节下标是 4000,仍落在 4001 字节范围内;若误分配 32000 bits 会越界。

Python 参考实现

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

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

from collections.abc import Callable


def bitmap_sort(get_num: Callable[[], int | None], put_num: Callable[[int], None]) -> None:
    """Read until None; valid distinct input values are in [0, 32000]."""
    bits = bytearray((32001 + 7) // 8)
    while True:
        value = get_num()
        if value is None:
            break
        if not 0 <= value <= 32000:
            raise ValueError("out-of-range value")
        bits[value >> 3] |= 1 << (value & 7)
    for value in range(32001):
        if bits[value >> 3] & (1 << (value & 7)):
            put_num(value)


if __name__ == "__main__":
    source = iter([32000, 0, 8])
    output = []
    bitmap_sort(lambda: next(source, None), output.append)
    assert output == [0, 8, 32000]

复杂度

读 N 个数 O(N),扫完整个值域 M=32001 为 O(M),总 O(N+M) 时间;位图 ceil(M/8)=4001 字节,外加常数工作空间。输出文件容量 O(N)。

易错点与追问

容易失分的边界

  • 值域为 0..32000 共 32001 个值,位图少分配一位。
  • 把题目无重复改成有重复仍用 bitset 并声称保留原频次。
  • 边读边输出无法保证有序。
  • 假定 getNum 的 EOF 一定是 -1;题目未明确 helper 细节,训练版明确用 None。

继续深挖

  • 如果数值范围是 0..10^12 而 N 很稀疏,为什么位图不合适?
  • 若输入有重复且要输出重复,计数桶或外排如何选?
  • 如果 PutNum 必须流式立即调用且不能等读完,是否仍能保证排序?
✓已复制微信号!