题目重点:将平均值约束化成零和,记录最早相同前缀。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 输入值为整数,target为精确有理数,建议Fraction或字符串;不把二进制float的近似当精确十进制。
- 返回最长非空半开区间;并列取最早。无解返回(0,0)。
解题路线
- 写S=p/q,将每个值变成qx−p。长度m区间的变换和为qΣx−mp,等于0恰好意味着均值p/q。
- 累计变换前缀。相同前缀之间零和;每种前缀只保存最早位置,才能对当前右端形成最长区间。
- 数据可负,窗口均值没有单调性,所以不能用超过S就收缩的普通滑窗。流式只需前缀与哈希,若要求返回原内容还要另存数据。
手动走一遍
[1,3,2,8],target=2:前3项均值2,变换前缀0,−1,0,0,6,最早0位置让长度3胜出。[1,2],S=3/2时使用2x−3得到−1,+1,精确识别全区间。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
from fractions import Fraction
def longest_mean(a, target):
target = Fraction(target)
p, q = target.numerator, target.denominator
first, prefix, best = {0: 0}, 0, (0, 0)
for end, x in enumerate(a, 1):
prefix += q * x - p
if prefix in first:
start = first[prefix]
if end - start > best[1] - best[0]:
best = (start, end)
else:
first[prefix] = end
return best
复杂度
期望O(n)时间、O(n)前缀表空间(每个整数运算位成本另计);完整无界流不能保证固定内存。
易错点与追问
容易失分的边界
- 同前缀覆盖成最新下标会缩短答案。
- 用epsilon比较哈希键不是等价关系,也不能直接用浮点相等来证明正确。
继续深挖
- 若均值在区间[A,B]内,为什么哈希相等法不够?
- 限定窗口长度≤W时,最早前缀需要怎样维护和过期?
