我有一组随机排序的唯一封闭区间 R0...Rn-1,其中
Ri = [r1i, r2i] (r1i <= r2i)
随后,一些范围重叠(部分或完全),因此需要合并。
我的问题是,用于合并这些范围的最佳算法或技术是什么。提供执行此合并操作的算法示例或链接到库的示例将非常有用。
你需要做的是:
按字典顺序排序项,其中范围键为 [r_start, r_end]
迭代排序后的列表并检查当前项是否与下一项重叠。如果它们重叠,则将当前项扩展为 r[i].start,r[i+1].end,然后转到下一个项目。如果不重叠,则将当前项添加到结果列表中并移动到下一项。
以下是示例代码:
vector<pair<int, int> > ranges;
vector<pair<int, int> > result;
sort(ranges.begin(),ranges.end());
vector<pair<int, int> >::iterator it = ranges.begin();
pair<int,int> current = *(it)++;
while (it != ranges.end()){
if (current.second > it->first){ // you might want to change it to >=
current.second = std::max(current.second, it->second);
} else {
result.push_back(current);
current = *(it);
}
it++;
}
result.push_back(current);
Boost.Icl 可能对您有用。
该库提供了一些模板,您可以在您的情况下使用:
这里有一个 示例,演示如何使用该库合并区间:
interval<Time>::type night_and_day(Time(monday, 20,00), Time(tuesday, 20,00));
interval<Time>::type day_and_night(Time(tuesday, 7,00), Time(wednesday, 7,00));
interval<Time>::type next_morning(Time(wednesday, 7,00), Time(wednesday,10,00));
interval<Time>::type next_evening(Time(wednesday,18,00), Time(wednesday,21,00));
// An interval set of type interval_set joins intervals that that overlap or touch each other.
interval_set<Time> joinedTimes;
joinedTimes.insert(night_and_day);
joinedTimes.insert(day_and_night); //overlapping in 'day' [07:00, 20.00)
joinedTimes.insert(next_morning); //touching
joinedTimes.insert(next_evening); //disjoint
cout << "Joined times :" << joinedTimes << endl;
以及该算法的输出:
Joined times :[mon:20:00,wed:10:00)[wed:18:00,wed:21:00)
std::priority_queue
应该可以胜任,但我认为它不会比排序更快/...。毕竟,您按顺序遍历所有项目,因此最终它们会被排序。 - sthO(n*log(n)+2n):
r1_i -> r2_i
r1_i
进行快速排序r1_i
值选择最大的r2_i
值r2_i
值,可以跳过所有比r2_i
小的后续r1_i
值andand
的观点,理论上没有区别!但是说“在实践中有所不同”并不是毫无意义的。在实践中,实践就是一切,而那些在理论上没有区别的大O符号可能会彻底毁掉你! - Bernd Elkemannjethro的回答有误。应该是
if (current.second > it->first){
current.second = std::max(current.second, it->second);
} else {
我的算法不使用额外的空间,而且非常轻量级。我使用了2指针
方法。'i'不断增加,而'j'跟踪正在更新的当前元素。
这是我的代码:
bool cmp(Interval a,Interval b)
{
return a.start<=b.start;
}
vector<Interval> Solution::insert(vector<Interval> &intervals, Interval newInterval) {
int i,j;
sort(intervals.begin(),intervals.end(),cmp);
i=1,j=0;
while(i<intervals.size())
{
if(intervals[j].end>=intervals[i].start) //if overlaps
{
intervals[j].end=max(intervals[i].end,intervals[j].end); //change
}
else
{
j++;
intervals[j]=intervals[i]; //update it on the same list
}
i++;
}
intervals.erase(intervals.begin()+j+1,intervals.end());
return intervals;
}
Interval可以是一个具有数据成员“start”和“end”的公共类或结构体。 编码愉快 :)
我知道这是原始答案被接受后很长一段时间。但在c++11中,我们现在可以按以下方式构造priority_queue
priority_queue( const Compare& compare, const Container& cont )
在O(n)次比较中。
请参见https://en.cppreference.com/w/cpp/container/priority_queue/priority_queue以获取更多详细信息。
因此,我们可以在O(n)时间内创建一对的priority_queue(最小堆)。在O(1)时间内获取最低间隔,并在O(log(n))时间内弹出它。因此,总时间复杂度接近于O(nlog(n) + 2n) = O(nlogn)
r[i].end + 1 == r[i+1].start
时?实际上,这些范围也可以合并。 - abyss.7