区间树中的最大非重叠区间
Posted
技术标签:
【中文标题】区间树中的最大非重叠区间【英文标题】:Maximum non-overlapping intervals in a interval tree 【发布时间】:2013-11-08 02:31:22 【问题描述】:给定一个时间间隔列表,我需要找到一组最大不重叠间隔。
例如,
如果我们有以下间隔:
[0600, 0830], [0800, 0900], [0900, 1100], [0900, 1130],
[1030, 1400], [1230, 1400]
还规定时间必须在[0000, 2400]
范围内。
最大不重叠的间隔集是[0600, 0830], [0900, 1130], [1230, 1400]
。
我了解最大集包装是 NP-Complete。我想确认我的问题(间隔仅包含开始和结束时间)是否也是 NP-Complete。
如果是这样,有没有办法在指数时间内找到最佳解决方案,但需要更智能的预处理和修剪数据。或者如果有一个相对容易实现的固定参数易处理算法。我不想使用近似算法。
【问题讨论】:
“最大”是指间隔的最大个数还是间隔的最长总持续时间?您的示例解决方案是 3 个间隔,总持续时间为 6.5 小时。是什么让它最大,3 还是 6.5? 【参考方案1】:这不是一个 NP 完全问题。我可以想到一个O(n * log(n))
算法使用动态规划来解决这个问题。
假设我们有 n 个区间。假设给定的范围是S
(在你的情况下是S = [0000, 2400]
)。要么假设所有区间都在S
内,要么在线性时间内消除所有不在S
内的区间。
预处理:
按开始点对所有区间进行排序。假设我们得到一个包含 n 个区间的数组A[n]
。
这一步需要O(n * log(n))
时间
对于区间的所有终点,找出其后最小起点的索引。假设我们得到一个 Next[n]
的数组 n
整数。
如果对于区间i,
的终点不存在这样的起点,我们可以将n
分配给Next[i]
。
我们可以在O(n * log(n))
时间通过枚举所有区间的n个端点来做到这一点,并使用二进制搜索来找到答案。也许存在线性方法来解决这个问题,但这没关系,因为上一步已经花费了O(n * log(n))
时间。
DP:
假设[A[i].begin, S.end]
范围内的最大非重叠间隔为f[i]
。那么f[0]
就是我们想要的答案。
还假设f[n] = 0
;
状态转移方程:
f[i] = maxf[i+1], 1 + f[Next[i]]
很明显,DP 步骤需要线性时间。
上面的解决方案是我第一眼看到问题时想出的解决方案。之后,我还想出了一个更简单(但在大 O 表示法意义上并不快)的贪婪方法:
(使用与上述 DP 方法相同的符号和假设)
预处理:按所有区间的结束点排序。假设我们得到一个包含 n 个区间的数组B[n]
。
贪婪:
int ans = 0, cursor = S.begin;
for(int i = 0; i < n; i++)
if(B[i].begin >= cursor)
ans++;
cursor = B[i].end;
以上两种解决方案都是我想到的,但是你的问题也称为活动选择问题,可以在***http://en.wikipedia.org/wiki/Activity_selection_problem找到。
另外,算法简介在 16.1 中深入讨论了这个问题。
【讨论】:
我对第 1 点的第二个项目符号有点困惑。你是说我们需要为下一个可能的间隔创建一个新数组吗?这是Next[n]
还是Next[n]==A[n]
?也许你可以再写一些代码来澄清一下?以上是关于区间树中的最大非重叠区间的主要内容,如果未能解决你的问题,请参考以下文章