题目重点:删除位置 i 后其右侧元素下标奇偶翻转;维护左右奇偶和,线性找出全部可删除位置。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 下标从 0 开始,偶数下标为 0,2,...;数组元素可正可负。
- 训练接口返回所有满足条件的原始下标;若面试官只要个数,返回列表长度即可。
- 删除一个元素是必须操作;对空数组返回空列表。若原数组长 1,删除后两边空和均为 0,所以唯一位置有效。
解题路线
- 分别维护删除点左边与右边的奇偶位置和。扫描到 i 时先从右侧对应奇偶和移除 values[i],表示该元素已删。
- 删除 i 后左侧下标不变,右侧所有原下标减 1,奇偶正好交换。因此新偶数和=left_even+right_odd,新奇数和=left_odd+right_even。
- 比较两者,相等则记录 i;然后把 values[i] 加到左侧对应原奇偶和,处理下一个候选。
- 每个元素只从右侧移到左侧一次,且每步常数工作;无需为每个 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 的什么性质?
- 如果要求删除两个不相邻元素,简单单扫描还够吗?
