取代表开始/结束的数字对,并删除重叠

Taking pairs of numbers representing begin/end, and removing overlaps

本文关键字:删除 重叠 数字 开始 结束 取代      更新时间:2023-10-16

我有一个表示[开始,结束]范围的对数组。 可以假定数组已经按"开始"字段排序。

我想生成一个新数组,其中删除了所有重叠,并根据需要创建了其他对。

例如,假设数组包含以下对:

[1,3],[2,5],[7,15],[8,9],[12,19]

输出应如下所示:

[1,2],[2,3],[3,5],[7,8],[8,9],[9,12],[12,15],[15,19]

最终,输出数组应该完全不包含重叠。

不超过 O(m( 的最佳解决方案是什么,其中 m 是输出数组中所需的条目数? 我想我在 O(n^2( 中看到了一种方法,其中 n 是输入数组中的条目数,但必须有更好的方法。

最终实现将在 C++11 中使用双精度对的向量,尽管伪代码解决方案很好。

编辑:

我感谢所有回复,但我礼貌地提前请求不要发布任何依赖于特定框架或库的解决方案,除非这些框架是标准 c++11 的一部分。

首先,我将解决一个相关问题;生成覆盖同一区域且没有邻接或重叠的合并间隔。

遍历输入数组。 从第一个元素开始。 记录高水位(间隔结束(和lowater(间隔开始(。

继续前进。 每个元素,如果它重叠间隔,则延伸高水位。 如果没有,则输出高水和lowater作为间隔,然后记录新的高点和lowater。

这需要 O(n( 时间输入。

必须读取输入的每个元素,因为它们中的任何一个都可以从其起始位置到结束并更改结果。 所以这是O-最优的。


这会将间隔合并到您可以制作的最大连续间隔中;您希望将所有"边"或"接缝"保存在原始间隔中。 要解决您的规格,只需跟踪接缝(按顺序(并在这些接缝处打破生成的间隔。 "洛沃特"接缝总是伴随着价值的增加;高水接缝可能没有。 因此,一组有序的接缝应该有效。 这是O(nlgn(可悲的,由于集合。


// half open
struct interval {
int lowater = 0;
int highwater = 0;
bool empty() const {
return lowater == highwater;
}
friend std::ostream& operator<<( std::ostream& os, interval i ) {
return os << "[" << i.lowater << "," << i.highwater << "]";
}
};

template<class Range, class Out>
void build_intervals( Range&& in, Out out ) {
std::optional<interval> current;
std::set<int> seams;
auto dump_interval = [&](interval i){
if (i.empty()) return;
*out = i;
};
auto dump_current = [&]{
if (!current) return;
//    std::cout << "Dumping " << *current << " with seams: {";
for (int seam:seams) {
//        std::cout << seam << ",";
dump_interval({ current->lowater, seam });
current->lowater = seam;
}
//    std::cout << "}n";
dump_interval( *current );
current = std::nullopt;
seams.clear();
};
for (auto&& e : in) {
if (current && e.lowater <= current->highwater) {
seams.insert(e.lowater);
seams.insert(e.highwater);
//        std::cout << "No gap between " << *current << " and " << e << "n";
current->highwater = (std::max)(e.highwater, current->highwater);
//        std::cout << "Combined: " << *current << "n";
continue;
}
if (!current) {
//        std::cout << "New current " << e << "n";
} else {
//        std::cout << "Gap between " << *current << "  and " << e << "n";
dump_current();
}
current = e;
seams.insert(e.lowater);
seams.insert(e.highwater);
}
dump_current();
}

活生生的例子。

我想出了这样的东西,如果它在 O(n( 时间内完成,只需添加几个。我只是不确定最后一个元素,我的输出:

[1 : 2], [2 : 3], [3 : 5], [7 : 8], [8 : 9], [9 : 12], [12 : 15], [15 : 19]

也许它会有所帮助:

std::vector<std::pair<int, int>> noOverlaps(std::vector<std::pair<int, int>>& input) {
if (input.size() <= 1) {
return input;
}
std::vector<std::pair<int, int>> result;
result.push_back(input[0]);
for (int i = 1; i < input.size(); ++i) {
//If overlap
if (input[i].first < result.back().second) {
auto lastOne = result.back();
result.pop_back();
result.push_back(std::make_pair(lastOne.first, input[i].first));
if (lastOne.second > input[i].second) {
result.push_back(std::make_pair(input[i].first, input[i].second));
result.push_back(std::make_pair(input[i].second, lastOne.second));
} else {
result.push_back(std::make_pair(input[i].first, lastOne.second));
result.push_back(std::make_pair(lastOne.second, input[i].second));
}
} else {
result.push_back(input[i]);
}
}
return result;
}

更新 1如上面的评论中所述,不适用于多个重叠间隔,因此可以通过吞咽相互包含并运行相同算法的间隔来改进上述解决方案:

std::vector<std::pair<int, int>> noOverlaps(std::vector<std::pair<int, int>>& origInput) {
if (origInput.size() <= 1) {
return origInput;
}
std::vector<std::pair<int, int>> result;
std::vector<std::pair<int, int>> input;
input.push_back(origInput[0]);
for (int i = 1; i < origInput.size(); ++i) {
if (input[i-1].first <= origInput[i].first && input[i-1].second >= origInput[i].second) {
continue;
}
input.push_back(origInput[i]);
}
result.push_back(input[0]);
for (int i = 1; i < input.size(); ++i) {
//If overlap
if (input[i].first < result.back().second) {
auto lastOne = result.back();
result.pop_back();
result.push_back(std::make_pair(lastOne.first, input[i].first));
if (lastOne.second > input[i].second) {
result.push_back(std::make_pair(input[i].first, input[i].second));
result.push_back(std::make_pair(input[i].second, lastOne.second));
} else {
result.push_back(std::make_pair(input[i].first, lastOne.second));
result.push_back(std::make_pair(lastOne.second, input[i].second));
}
} else {
result.push_back(input[i]);
}
}
return result;
}

但这需要 2xO(n( 的空间复杂性,并且代码并不好。

所以我只是想知道这还不够:

std::vector<std::pair<int, int>> noOverlaps2(std::vector<std::pair<int, int>>& origInput) {
if (origInput.size() <= 1) {
return origInput;
}
int low = origInput[0].first, high = origInput[0].second;
std::vector<std::pair<int, int>> result;
for (int i = 1; i < origInput.size(); ++i) {
if (high < origInput[i].first) {
result.emplace_back(low, high);
low = origInput[i].first;
high = origInput[i].second;
} else {
high = std::max(origInput[i].second, high);
}
}
result.emplace_back(low, high);
return result;
}

对于您的数据,它给出了输出:[1 : 5], [7 : 19]但它消除了重叠。