环形/周期性区间的最大相交数求解方案问询
解决环形/周期性区间的最大相交数问题
嘿,这个问题很有意思!既然你已经熟悉线性区间的解法,那我们可以把环形问题转化为线性问题来处理,核心思路是打破环形的“循环”特性,把它变成我们能处理的线性场景,下面分两种高效的方法来讲解:
方法一:双倍长度线性展开法(直观易实现)
这种方法的核心是把环形区间“展开”成两倍周期长度的线性空间,这样环形上的任意连续周期段,都能对应到这个线性空间里的一个长度为周期的窗口。具体步骤如下:
步骤1:确定周期长度
首先明确环形的周期长度,记为L(比如如果是0~20的环形,L=20)。
步骤2:生成事件点集合
对于每个环形区间[s, e]:
- 如果
s <= e(不跨周期端点):生成两个事件点:(s, +1)(区间开始,覆盖数+1)、(e, -1)(区间结束,覆盖数-1);同时复制这两个事件点,把时间加上L,得到(s+L, +1)、(e+L, -1)。 - 如果
s > e(跨周期端点,比如[18,3]在L=20时):同样生成原事件点(s, +1)、(e, -1),以及平移后的(s+L, +1)、(e+L, -1)。
注意:如果你的线性解法中是用
e+1作为减1的触发点(避免区间端点重复计算),记得保持一致,这里用e是假设区间是闭区间[s,e]。
步骤3:排序事件点
把所有生成的事件点按时间从小到大排序;如果时间相同,优先处理+1的事件(和线性解法一致,确保区间端点处的覆盖数计算正确)。
步骤4:滑动窗口统计最大覆盖数
用双指针维护一个长度为L的滑动窗口:
- 初始化左指针
left=0,当前覆盖数current=0,最大相交数max_count=0。 - 遍历每个右指针指向的事件点:
- 将当前事件的delta(+1或-1)加到
current上。 - 移动左指针,移除所有时间 <= 当前事件时间 -
L的事件:每次将current减去左指针事件的delta,然后左指针右移。 - 更新
max_count为当前current和max_count中的较大值。
- 将当前事件的delta(+1或-1)加到
这个max_count就是环形区间的最大相交数。
方法二:分场景计算法(更高效,适合大数据量)
如果你的区间数量很大,双倍展开可能会占用较多内存,这时候可以分两种场景计算,取最大值:
场景1:最大相交数出现在非跨端点的线性段
直接用你熟悉的线性解法处理所有区间:
- 把跨周期的区间拆成两个线性区间(比如
[s,e](s>e)拆成[s,L]和[0,e])。 - 用标记起止点、排序、遍历统计的方法,计算线性场景下的最大相交数,记为
max_linear。
场景2:最大相交数出现在跨周期端点的位置
这种情况的相交数等于总区间数减去“完全落在环形某段空白区”的区间数量的最小值:
- 统计总区间数
total = 所有区间的数量。 - 收集所有跨周期区间的
e(右端点,0L)和`s`(左端点,0L),我们要找的空白区是环形上未被任何跨周期区间覆盖的部分,也就是所有[e_i, s_i]的交集(所有跨周期区间都不覆盖的区域)。 - 统计完全落在这个空白区里的非跨周期区间的数量,找到这个数量的最小值
min_gap。 - 跨端点场景的最大相交数为
total - min_gap(因为所有跨周期区间都覆盖端点位置,加上非跨周期区间中不落在空白区的部分)。
最终结果
环形区间的最大相交数 = max(max_linear, total - min_gap)
例子验证
比如你给出的线性区间[1,6]、[2,5]、[5,10]、[12,17],假设周期L=20(无跨周期区间):
- 方法一:双倍展开后滑动窗口统计的最大覆盖数是3,和线性结果一致。
- 方法二:
max_linear=3,由于没有跨周期区间,跨端点场景的计算不适用,直接取max_linear即可。
内容的提问来源于stack exchange,提问作者kingW3
相关产品推荐
相关产品推荐

