题目重点:返回活跃人数恰为1的全部片段,不是所有有人在线的并集。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练代码输入半开区间,每区间代表一个不同人的一次活动;若同一人有多个区间,先按人合并,避免同一人自重叠计两人。
- 零长区间不占用,端点a≤b;输出相接且同满足“人数1”的片段可合并,即使活跃身份发生变化。
解题路线
- 每起点+1,终点−1,聚合同一时刻事件。排序后,处理时刻t的事件前,active适用于[last,t)。
- 当active=1输出该片段,再应用t的总delta。这样相同结束/开始边界不会产生瞬时双人。
- 如果需要返回“谁唯一在线”,另维护活跃身份集合,并且不同身份的相接片段不能合并。当前计数结果不含身份。
手动走一遍
A[1,4),B[3,6):恰一人为[1,3)和[4,6),[3,4)两人不输出。A[1,2),B[2,3):人数全程1,可合并[1,3);若要身份则分两段。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
def covered_once(intervals):
events = {}
for a, b in intervals:
if a > b:
raise ValueError("reversed interval")
if a != b:
events[a] = events.get(a, 0) + 1
events[b] = events.get(b, 0) - 1
active, last, result = 0, None, []
for t in sorted(events):
if last is not None and last < t and active == 1:
if result and result[-1][1] == last:
result[-1] = (result[-1][0], t)
else:
result.append((last, t))
active += events[t]
last = t
return result
复杂度
O(nlogn)时间、O(n)事件/结果空间。按人预合并成本也按该人区间数排序计。
易错点与追问
容易失分的边界
- 闭区间的单个端点是否算时间片需另定,连续时间通常用半开。
- 重复同人区间未经合并会把“人数”误计为“记录数”。
继续深挖
- 返回恰K人在线的时段,扫描条件如何改?
- 在线增删区间和多次查询要怎样维护计数分布?
