用于在重叠间隔序列中找到最大和的算法

时间:2010-07-14 03:35:07

标签: algorithm sum max intervals

我想要解决的问题是在数字行上有一个间隔列表,每个间隔都有一个预定义的分数。我需要返回最大可能的总分。

抓住的是间隔重叠,重叠间隔我只能使用一个。这是一个例子。

Intervals   - Score  
   0- 5     -  15  
   4- 9     -  18  
  10-15     -  12  
   8-21     -  19  
  25-30     -  25    

这里,间隔0-5,4-9和8-21重叠 间隔10-15和8-21也重叠 最大金额为55(18 + 12 + 25)。

重要的是要注意,我们选择第一批重叠间隔的间隔4-9,即使它没有三者的最高分数。

这是因为选择间隔8-21将阻止我们稍后使用间隔10-15,从而减少总和(在这种情况下,总和将是19 + 25 = 44)。

我正在寻找这个问题的O(nlogn)或O(n)解决方案。我认为可以使用动态编程,但我可能错了。有人可以建议一个可以解决这个问题的解决方案/算法吗?

编辑:间隔没有特定的顺序。

6 个答案:

答案 0 :(得分:24)

这是interval scheduling的加权变体;它可以O(N log N)dynamic programming解决。

让间隔为g(start, stop, score),让它们按stop排序。为简单起见,我们现在假设所有stop都是唯一的。

当我们被允许使用best[i]时,g[1], ..., g[i]是我们可以获得的最佳分数。当然,我们不必全部使用它们,通常我们不能,因为我们使用的间隔子集必须是非重叠的。

  • 显然best[0] = 0。也就是说,由于我们不能使用任何间隔,我们得到的最高分是0。
  • 对于任何1 <= k <= N,我们都有:
    • best[k] = max( best[k-1], best[j] + g[k].score ),在哪里
      • j是最大的索引,g[j].stop < g[k].startj可能为零)

也就是说,鉴于我们被允许使用g[1], ... g[k],我们能做的最好的就是更好地评分这两个选项:

  • 我们不包含g[k]。因此,此选项的分数为best[k-1]
    • ...因为这是我们用g[1], ... g[k-1]
    • 做的最好的事情
  • 我们包含g[k],在其左侧,我们尽可能地使用与g[k]不重叠的所有基因,即所有g[1], ..., g[j],其中g[j].stop < g[k].start }和j尽可能大。因此,此选项的分数为best[j] + g[k].score

(注意上述等式中包含的动态规划的最优子结构和重叠子问题组成部分)。

问题的总体答案是best[N],即当我们被允许使用所有基因时我们可以获得的最佳分数。哎呀,我说基因了吗?我的意思是间隔。

这是O(N log N)因为:

  • 对所有间隔进行排序需O(N log N)
  • 使用二进制搜索查找每个j的{​​{1}}为k

如果几个基因可以具有相同的O(log N)值,则没有任何变化:您仍然需要搜索最右边的stop。在例如Python bisect_right很容易。在Java中,标准库二进制搜索不保证在关联的情况下返回哪个索引,您可以(在许多选项中)使用线性搜索(对于j最坏情况性能)或其他系列进行跟踪二进制搜索以找到最合适的索引。

哎呀我再说基因了吗?我的意思是间隔。

相关问题

答案 1 :(得分:4)

首先,我认为最大值是59,而不是55.如果选择区间[0-5],[8-21]和[25,30],则得到15 + 19 + 25 = 59。您可以使用某种动态编程来处理这个问题。

首先,按起点对所有间隔进行排序,然后从结束到开始迭代。对于列表中的每个项目,您选择从该点到最后一个的最大总和为max(S[i]+S[j], S[i+1]),其中i是您所在的项目,j是项目后面的第一个非重叠项目(即是,其开头大于当前项目结束的第一个项目)。要加速算法,您需要存储每个元素的最大部分和S [j]。

为了澄清,让我按照这个解决你的例子。首先,对您的间隔进行排序:

 1:  0- 5 -  15
 2:  4- 9 -  18
 3:  8-21 -  19
 4: 10-15 -  12
 5: 25-30 -  25

所以,

 S[5] = 25
 S[4] = max(12+S[5], 25)=37
 S[3] = max(19+S[5], S[4])=max(19+25,37)=44
 S[2] = max(18+S[4], S[3])=max(18+37,44)=55
 S[1] = max(15+S[3], S[2])=max(15+44, 55)=59

这是this post中算法的改编,但不幸的是,没有很好的O(n)运行时间。每个条目与下一个条目重叠的简并列表将导致它为O(n ^ 2)。

答案 2 :(得分:0)

也许可以使用像this answer这样的方法,至少对于那个问题, O(n)。它意味着迭代一次间隔并跟踪那些仍然可以导致最佳最终解决方案的区间组合。

答案 3 :(得分:0)

听起来像是背包问题的一个变种。您可能会在搜索这些解决方案时找到一些灵感。

我们谈论了多少个间隔?如果它只有大约5(如你的例子),那么尝试每种组合可能更实际。如果更多的话,理想解决方案的近似值会怎样?同样,Knapsack解决方案(例如George Dantzig的贪婪近似算法)可能是一个很好的起点。

答案 4 :(得分:0)

我想到了这一点并提出了一些建议。

Interval Trees提供了一种有效的方法来查找与给定间隔重叠的所有间隔。遍历整个区间,我们可以找到给定区间的所有重叠区间。一旦我们有了这些,我们就可以找到得分最高的区间,存储它并继续前进。

构建树需要O(N Log N)时间,查找需要O(Log N)时间。因为我们查找所有元素,所以解决方案变为O(N Log N)。

但是,如果我们面对上述例子,其中一组中的最高得分间隔减少了总数,则算法失败,因为我们无法知道不应该事先使用最高得分间隔。显而易见的方法是在我们不确定的情况下计算两个(或所有)总数,但这会使我们回到潜在的O(N ^ 2)或更糟的解决方案。

答案 5 :(得分:0)

我想我们可以使用这种递归...

S[i]表示每个区间的分数
Interval[i]表示所有间隔

ResMax[i] = max(ResMax[i-1] + S[i] //if i is included
           ,max(R[i-1],S[i]) 
         )

我没有得到彻底的检查,但我应该相信。