题目重点:用区间端点长度连接左右区间,证明只读邻居时为何不会被内部旧长度误导,支持负坐标和重复查询。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 只插入不删除,坐标可负、可很大;重复建同一位置按no-op处理,这是本文明确的训练政策。
- 连续表示相邻整数差1;返回每次操作后的全局最长长度。
- 端点长度索引可以保留内部旧条目,但另用occupied集合判断是否重复。
解题路线
- 新位置x未占用时,若x−1已占用,它必是左侧区间的右端点,否则左区间会包含x,矛盾。同理x+1必是右区间左端点。这保证读到的长度是端点真值。
- 设左右长度L/R,新合并区间[x−L,x+R]长度L+1+R。把两端点长度更新为新长度,同时记x长度供初次单点和成员判断的说明;全局best只取max不会下降。
- 内部旧长度不用逐项刷新,因为今后只会读取某个待插入点的左右邻居,而这些邻居一旦被读取必是现有区间端点。删除会打破这个证明,因此此结构不支持任意拆区间。
- occupied和lengths分开,使“记录在dict中”的意义不被误解成当前端点;重复x直接输出旧best,不再次连接,否则会把同一区间重复相加并凭空增长。
- 坐标稀疏时不能建max−min大小的数组,哈希索引只存真正插入的坐标。大整数x±1在Python可直接处理;固定机器整数需检查端点溢出。
- 若还需返回最长区间,可在size更新best时保存新左右端点,并定义相同长度tie-break。在线删除需平衡树/区间集合等另一结构,而不是修改本代码几行就保证正确。
手动走一遍
插入[1,3,2,2,5,4]:最长长度[1,1,3,3,3,5]。插入2时读1/3的端点长度各1合成[1,3];重复2不变。插入4时左端邻居3提供长度3、右邻居5长度1,得到[1,5]。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
"""After each integer-coordinate insertion, return the longest occupied run.
Duplicates are no-ops; zero/negative coordinates are valid.
"""
def longest_house_runs(queries):
occupied = set()
lengths = {}
best = 0
output = []
for x in queries:
if not isinstance(x, int) or isinstance(x, bool):
raise ValueError("integer coordinate required")
if x not in occupied:
left = lengths.get(x - 1, 0)
right = lengths.get(x + 1, 0)
size = left + 1 + right
occupied.add(x)
lengths[x] = size
lengths[x - left] = size
lengths[x + right] = size
best = max(best, size)
output.append(best)
return output
复杂度
每次插入期望O(1),q次总期望O(q),空间O(U)其中U为不同坐标数。哈希最坏界依实现,大整数坐标还包含其位运算和存储成本。
易错点与追问
容易失分的边界
- 重复建房仍做合并。
- 逐个更新整个区间造成二次时间。
- 按最大坐标分配数组。
- 支持删除却仍相信旧端点证明。
继续深挖
- 怎样返回最长区间端点?
- 需要删除房屋如何换结构?
- 输入坐标重复应报错还是忽略?
- 如何用并查集作对照实现?
