【问题标题】:Algorithm for merging overlapping intervals合并重叠区间的算法
【发布时间】:2017-06-20 18:04:02
【问题描述】:

我一直在寻找一种有效的算法来合并动态间隔数组上的重叠间隔。例如,(开始时间,结束时间)明智,

[(1, 2), (4, 8), (3, 10)]

变成

[(1, 2), (3, 10)]

合并后,因为 (4, 8) 和 (3, 10) 重叠。重叠意味着两个区间的任何部分共享相同的时刻。

我知道当给出一个完整的数组时,可以在按开始时间升序对间隔进行排序后使用堆栈完成操作 (reference: geeksforgeeks)。但是这个算法只有在给定数组是非动态的时候才有效,但我正在寻找对动态数组有效的算法。例如,数组区间会频繁更新和插入,每次操作都要合并区间。

【问题讨论】:

  • 如果你的数组总是“合并”和排序,添加一个新区间的复杂度应该是 O(log n) (对于插入/合并的适当位置的二进制搜索)。跨度>
  • 您能否详细说明答案部分的完整算法。 @EugeneSh。

标签: arrays algorithm dynamic merge intervals


【解决方案1】:

保留一个区间的二叉搜索树 (BST),键是区间的起点。

对于要插入的任何新间隔:

  • 在 BST 中找到小于新区间起点的最大值(可以在 O(log n) 内完成)。

    该区间或下一个区间将与新区间重叠,或者不存在重叠(在这种情况下,我们只需插入)。

  • 可以有更多的区间与新的区间重叠,因此我们需要从这里迭代 BST 的其余部分(从上面找到的点开始)并将区间与任何重叠的区间合并。

虽然任何给定的插入在最坏的情况下都可能占用 O(n log n)(如果该间隔与例如每隔一个间隔重叠),但每次插入的摊销时间将为 O(log n)(因为我们可以计算删除元素的工作是插入元素工作的一部分,总共是 O(log n) 个工作)。

一些经过轻微测试的 C++ 代码这样做:

// set<pair<int, int> > can also be used, but this way seems conceptually simpler
map<int, pair<int, int> > intervals;

void insert(int left, int right)
{
  if (!intervals.empty())
  {
    // get the next bigger element
    auto current = intervals.upper_bound(left);
    // checking if not found is not needed because of decrement and how C++ iterators work
    // decrement to get next smaller one instead, but only if we're not that the beginning
    if (current != intervals.begin())
        --current;
    // skip current if it's entirely to the left of the new interval
    if (current->second.second < left)
        ++current;
    // update new starting point if there's an overlap and current is more to the left
    if (current != intervals.end() && current->first <= right)
        left = min(left, current->first);
    // iterate through while there's an overlap (deleting as we go)
    for (; current != intervals.end() && current->first <= right;
           current = intervals.erase(current))
        // update the end point of new interval
        right = max(right, current->second.second);
  }
  // insert our updated interval
  intervals[left] = make_pair(left, right);
}

// FYI: current->first is the start, current->second.second is the end

Live demo.

【讨论】:

    猜你喜欢
    • 2011-02-05
    • 1970-01-01
    • 2015-10-18
    • 1970-01-01
    • 2015-12-11
    • 2018-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多