题目重点:返回覆盖区间数最多的坐标,用扫描线处理同坐标起止,明确并列和闭区间边界。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练区间闭合[left,right],left≤right,返回(point,count);并列取最早坐标,空输入(None,0)。若题面为半开区间,事件顺序和点区间规则不同。
解题路线
- 分别累计每坐标startCount和endCount,排序所有不同端点。扫描到x先加起点,再计算峰值,最后减终点;闭区间终点在x仍参与覆盖。
- active表示从前坐标到x之前仍活跃的区间,加start后准确等于包含x的区间数。结束事件必须在观察后减去,否则[1,2]与[2,3]会漏掉x2共同覆盖。
- 为何只看端点足够?开区间间隔内覆盖数不变,新增覆盖只在起点发生;任意最大覆盖区段的最早合法点可取起点。因此端点扫描能找到全局最大并列最早。
- 只在active>best时更新point,sorted顺序自动保留最早;同坐标多个点区间同时start/end,先加后减也成立,不需要特殊分支。
- 如果题面只要number坐标,可只返回point;count用于检查与解释。不要返回最大数量替代位置,输出合同应明确。
手动走一遍
[1,2]、[2,3]、[2,2]在x2同时覆盖3个,返回(2,3)。[1,2]与[3,4]最大1,并列返回1;边界若半开则x2不再同时覆盖前两个,需要改合同。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
from collections import defaultdict
def maximum_overlap(intervals):
"""Closed intervals; returns (earliest max-count point,count), empty (None,0)."""
starts=defaultdict(int);ends=defaultdict(int)
for left,right in intervals:
if left>right:raise ValueError('reversed interval')
starts[left]+=1;ends[right]+=1
active=best=0;point=None
for x in sorted(starts.keys() | ends.keys()):
active+=starts[x]
if active>best:best=active;point=x
active-=ends[x]
return point,best
复杂度
O(N log N)时间/O(N)事件空间,扫描O(不同端点数)。若时间轴很大不可开长度为最大坐标的数组;压缩排序端点不依赖坐标数值范围。
易错点与追问
容易失分的边界
- 闭区间先减end会漏端点共同覆盖。
- 把最大重叠坐标与最少会议室/箭数量混成同输出。
继续深挖
- 若求所有最大覆盖区段,怎样保留端点和开闭信息?
- 在线添加删除区间,可用坐标压缩segment tree维护范围加和最大值,但未知新坐标如何处理?
