SWE · Stage 3 Coding

Oracle 已排序数组:原地最多保留 K 个重复值

用写指针在 O(n) 时间、O(1) 额外空间实现每个值最多出现 K 次,处理 K=0 和数组尾部语义。

题目重点:用写指针在 O(n) 时间、O(1) 额外空间实现每个值最多出现 K 次,处理 K=0 和数组尾部语义。

题意与假设

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

  • 返回有效前缀长度,新内容仅在 values[:length] 中有意义;原列表尾部可保留旧值,不需要实际缩短容器。
  • k≥0,负 k 报错;输入可空,值可为任意可比较整数。

解题路线

  1. write 指向下一个输出位置,依次读每个原值。若 write<k,则当前值总可保留。
  2. 否则将当前值与输出前缀中倒数第 k 个值比较:若相同,说明已有 k 个该值,应跳过;不同则写入 values[write] 并递增 write。
  3. 因为输入已排序,同值相邻;不变量是处理前缀后 values[:write] 已按原顺序保留每个值最多 k 个且长度最大。读取下标始终不小于写下标,原地写不会覆盖未来未读值。

手动走一遍

values=[1,1,1,2,2,3]、k=2,依次写入前两个 1、跳过第三个 1,最终有效前缀 [1,1,2,2,3],返回 5。k=0 时返回 0。

Python 参考实现

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

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

"""Keep at most k copies of each value in a sorted array, in place."""


def keep_at_most_k(values: list[int], k: int) -> int:
    if k < 0:
        raise ValueError("k must be nonnegative")
    if k == 0:
        return 0
    write = 0
    for value in values:
        if write < k or value != values[write - k]:
            values[write] = value
            write += 1
    return write

复杂度

每个元素读取一次,O(N) 时间、O(1) 额外空间;若要求物理删除列表尾部,Python 的切片删除会修改容器长度,但题目常以有效前缀长度为接口。

易错点与追问

容易失分的边界

  • 把 k 写死为 2,仅解决常见固定变体。
  • k=0 时访问 values[write−k],或对空数组越界。
  • 误认为需要把尾部也填零或删除,混淆逻辑长度与物理数组长度。

继续深挖

  • 如果数组未排序且仍要求保留原相对顺序,每个值最多 k 次,需要什么额外空间?
  • 若必须保留每个值最后 k 次而非前 k 次,扫描方向如何变化?
✓已复制微信号!