区间树中的最大非重叠间隔

时间:2013-11-08 02:31:23

标签: algorithm interval-tree

给定一个时间间隔列表,我需要找到最大非重叠间隔的集合。

例如,

如果我们有以下间隔:

[0600, 0830], [0800, 0900], [0900, 1100], [0900, 1130], 
[1030, 1400], [1230, 1400]

此外,时间必须在[0000, 2400]范围内。

最大非重叠间隔集是[0600, 0830], [0900, 1130], [1230, 1400]

据我所知,最大设定包装是NP-Complete。我想确认我的问题(包含仅包含开始和结束时间的间隔)是否也是NP-Complete。

如果是这样,有没有办法在指数时间内找到最佳解决方案,但需要更智能的预处理和修剪数据。或者如果有一个相对容易实现的固定参数易处理算法。我不想去寻找近似算法。

1 个答案:

答案 0 :(得分:25)

这不是NP-Complete问题。我可以想到使用动态编程的O(n * log(n))算法来解决这个问题。

假设我们有n个间隔。假设给定范围是S(在您的情况下,S = [0000, 2400])。假设所有区间都在S之内,或者在线性时间内消除S以内的所有区间。

  1. 处理前:

    • 按开始点对所有间隔进行排序。假设我们得到n个区间的数组A[n]
      • 此步骤需要O(n * log(n))时间
    • 对于所有间隔的终点,找到其后的最小起点的索引。假设我们得到Next[n]n整数的数组i,
      • 如果间隔n的结束点不存在此类起点,我们可能会将Next[i]分配给O(n * log(n))
      • 我们可以在O(n * log(n))时间内通过枚举所有间隔的n个终点来执行此操作,并使用二进制搜索来查找答案。也许存在线性方法来解决这个问题,但这并不重要,因为上一步已经花了[A[i].begin, S.end]时间。
  2. DP:

    • 假设范围f[i]中的最大非重叠间隔为f[0]。然后f[n] = 0就是我们想要的答案。
    • 还假设f[i] = max{f[i+1], 1 + f[Next[i]]};
    • 状态转换方程:
      • B[n]
    • 很明显DP步骤需要线性时间。
  3. 上面的解决方案是我第一眼看出问题的解决方案。在那之后,我还想出了一种更简单的贪婪方法(但在大O符号意义上并不快):

    (使用与上述DP方法相同的符号和假设)

    1. 预处理:按结束点对所有间隔进行排序。假设我们得到n个区间的数组int ans = 0, cursor = S.begin; for(int i = 0; i < n; i++){ if(B[i].begin >= cursor){ ans++; cursor = B[i].end; } }

    2. 贪婪:

      {{1}}
    3. 以上两个解决方案出自我的想法,但您的问题也称为活动选择问题,可在维基百科http://en.wikipedia.org/wiki/Activity_selection_problem上找到。

      此外,算法简介在16.1中深入讨论了这个问题。