SWE / SDE · Phone Screen Coding

Microsoft 删除一个元素使奇偶下标和相等:后缀翻转与线性扫描

删除位置 i 后其右侧元素下标奇偶翻转;维护左右奇偶和,线性找出全部可删除位置。

题目重点:删除位置 i 后其右侧元素下标奇偶翻转;维护左右奇偶和,线性找出全部可删除位置。

题意与假设

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

  • 下标从 0 开始,偶数下标为 0,2,...;数组元素可正可负。
  • 训练接口返回所有满足条件的原始下标;若面试官只要个数,返回列表长度即可。
  • 删除一个元素是必须操作;对空数组返回空列表。若原数组长 1,删除后两边空和均为 0,所以唯一位置有效。

解题路线

  1. 分别维护删除点左边与右边的奇偶位置和。扫描到 i 时先从右侧对应奇偶和移除 values[i],表示该元素已删。
  2. 删除 i 后左侧下标不变,右侧所有原下标减 1,奇偶正好交换。因此新偶数和=left_even+right_odd,新奇数和=left_odd+right_even。
  3. 比较两者,相等则记录 i;然后把 values[i] 加到左侧对应原奇偶和,处理下一个候选。
  4. 每个元素只从右侧移到左侧一次,且每步常数工作;无需为每个 i 重建数组。

手动走一遍

[2,1,6,4] 删除下标 1 的 1 后得 [2,6,4],新偶数位和 2+4=6,奇数位和 6。扫描 i=1 时,左偶=2;右原偶=6、右原奇=4,翻转后新偶=2+4=6,新奇=0+6=6。

Python 参考实现

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

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

from collections.abc import Sequence


def balanced_removal_indices(values: Sequence[int]) -> list[int]:
    """Indices whose deletion balances even/odd indexed sums afterward."""
    right_even = sum(values[::2])
    right_odd = sum(values[1::2])
    left_even = left_odd = 0
    answer = []
    for i, value in enumerate(values):
        if i % 2 == 0:
            right_even -= value
        else:
            right_odd -= value
        # Suffix indices shift left and their parity flips after deletion.
        if left_even + right_odd == left_odd + right_even:
            answer.append(i)
        if i % 2 == 0:
            left_even += value
        else:
            left_odd += value
    return answer


if __name__ == "__main__":
    assert balanced_removal_indices([2, 1, 6, 4]) == [1]

复杂度

初始化左右总和 O(n),扫描 O(n),总 O(n) 时间、O(1) 工作空间,若输出所有下标则答案本身最坏占 O(n)。

易错点与追问

容易失分的边界

  • 只把被删元素从对应奇偶总和扣除,忽略右侧下标全部翻转。
  • 把 i 本身同时算进左、右两侧。
  • 只针对非负数设计滑窗;此题有负数也照样适用。
  • 题目未明确返回类型,不应把训练版‘返回所有索引’冒充原始接口。

继续深挖

  • 若要返回满足条件的位置个数,如何保持 O(1) 额外空间?
  • 删除连续长度 k 的区间后,右侧奇偶是否翻转取决于 k 的什么性质?
  • 如果要求删除两个不相邻元素,简单单扫描还够吗?
✓已复制微信号!