题目重点:将 A 变 B,只能对某个闭前缀或闭后缀整体 +1;从差分的正负变化推导可达条件与最优操作数。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练版前缀 [0..i] 与后缀 [i..n−1] 都包含 i;题目样例的两端单元素操作与此一致,但中间端点仍需现场确认。
- 只能加 1,不能减;数组可含负数但差值 d[i]=B[i]−A[i] 必须非负。
- 不可达时返回 -1;空数组无需操作返回 0。
解题路线
- 令 d=B−A。每个前缀操作在其结束点后使 d 的所需操作覆盖数下降 1;每个后缀操作在其开始点使覆盖数上升 1。
- 从左到右看 d 的变化:正跳变 Δ 必须至少有 Δ 个后缀从该处开始;负跳变 -Δ 必须至少有 Δ 个前缀在前一处结束。
- 设所有负跳变之和为 neg、正跳变之和为 pos。位置 0 的 d[0] 次覆盖必须足够供应将来要结束的 neg 个前缀,即 d[0]≥neg;且每个 d[i]≥0。若不满足,无法实现。
- 若满足,可先安排 neg 个合适的前缀及 d[0]−neg 个覆盖全数组的后缀,再在每个正跳变点开启相应后缀;操作总数 d[0]+pos,为下界且可构造达到。
- 直接扫描差分即可,无需模拟每次加一。
手动走一遍
题目 A=[2,3,4]、B=[3,3,5],d=[1,0,1]。负跳变总量 1、正跳变总量 1,d[0]=1 足够;最少 1+1=2,分别对首元素的前缀、末元素的后缀加一。d=[0,1,0] 虽每项非负,但需要在最后结束一个前缀而起点没有前缀可用,故不可达。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
from collections.abc import Sequence
def minimum_prefix_suffix_increments(a: Sequence[int], b: Sequence[int]) -> int:
"""Add 1 to an inclusive prefix or suffix; return -1 if impossible."""
if len(a) != len(b):
raise ValueError("arrays must have equal length")
if not a:
return 0
diff = [target - original for original, target in zip(a, b)]
if any(value < 0 for value in diff):
return -1
positive = sum(max(0, diff[i] - diff[i - 1]) for i in range(1, len(diff)))
negative = sum(max(0, diff[i - 1] - diff[i]) for i in range(1, len(diff)))
if diff[0] < negative:
return -1
return diff[0] + positive
if __name__ == "__main__":
assert minimum_prefix_suffix_increments([2, 3, 4], [3, 3, 5]) == 2
复杂度
构造差值及扫描 O(n) 时间、O(n) 额外空间;若边读 A/B 边处理且只保存前一个差值,可降为 O(1) 工作空间。实际输出完整操作序列可能有 Θ(答案) 项。
易错点与追问
容易失分的边界
- 只检查 B[i]≥A[i] 就断言可达,[0,1,0] 是反例。
- 把前缀和后缀 +1 错当任意区间 +1,得到过小答案。
- 把一次加一覆盖的所有元素分别计费,重复算操作数。
- 未明确 i 是否包含在操作区间以及不可达输出口径。
- 若操作次数可远超 32 位整型,在固定宽度语言需用足够大的整数。
继续深挖
- 若同时允许 -1 操作,最优值如何变化?
- 若只允许真前缀/真后缀、不许覆盖全数组,哪些可达条件需要改?
- 如何输出一组最少操作的端点,并保证输出顺序正确?
