让我说我有一系列间隔对。 v = {(1,4),(5,10),(11,13),(14,25)}
现在让我们说我的号码是20,我想分开那对是20,或者我想删除这对(14,25)并添加新的两对 - (14,20)和(21,25)。如何在c ++中执行此操作,或者只能如何搜索这些间隔并查找数字20的区间。
我的想法是创建对的向量,我将保持我的间隔,但我不知道如何分割间隔,我必须在日志时间,所以我必须使用二元搜索。
答案 0 :(得分:0)
在这种情况下搜索使用
std::upper_bound() or std::lower_bound()
获取要更改并继续的间隔索引。我在codeforces上解决了一个类似的问题,但我只是想告诉索引数字落在哪里。
答案 1 :(得分:0)
以下是@karan建议的使用std::lower_bound
的可能解决方案;如果使用向量,搜索是在日志时间而不是插入。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<std::pair<int, int> > input = { {1,4}, {5,10}, {11,13}, {14,25} };
struct LessInterval {
bool operator()(const std::pair<int, int>& fst, const std::pair<int, int>& snd)
{ return fst.second < snd.first; }
};
int key = 20;
// lower_bound uses a dichotomic search in log_2(N)
auto locateIter = std::lower_bound(input.begin(), input.end(),
std::make_pair(key, key), LessInterval());
if (locateIter != input.end()) {
// modifications on vector can be linear in N; you can consider std::set instead
if (locateIter->first <= key && key <= locateIter->second) {
if (key == locateIter->first) {
if (locateIter->second == key)
input.erase(locateIter);
else
locateIter->first = key+1;
}
else if (key == locateIter->second)
locateIter->second = key-1;
else {
int second = locateIter->second;
locateIter->second = key-1;
input.insert(locateIter+1, std::make_pair(key+1, second));
};
}
};
std::cout << '{';
bool isFirst = true;
for(const auto& interval : input) {
if (!isFirst)
std::cout << ", ";
std::cout << '(' << interval.first << ',' << interval.second << ')';
isFirst = false;
};
std::cout << std::endl;
return 0;
}
答案 2 :(得分:0)
插入排序的数组数据结构不能比O(N)快,所以你需要其他东西,比如树,即std::set
或std::map
。这些类具有内置的排序和搜索功能。他们的成员lower_bound
和upper_bound
适合查找间隔。
有几种方法可以表示树中的间隔。您可以定义自己的class interval
,也可以使用std::pair
。最简单的方法是使用std::map<int, int>
,它是由第一个成员排序的std::pair<int, int>
树。我建议一个查找表,其中间隔上限是键,间隔下限是值。
map::upper_bound
接受一个数字并返回(迭代器)第一个大于它的条目。这适用于半开间隔:不是记录从14到25(包括14和25)的闭合间隔[14,25],而是使用半开区间[14,26],其从14到26不包括。当您搜索25时,upper_bound
将看到26并返回正确的条目。
intervals[ 26 ] = 14; // Insert interval [14, 25]
intervals[ 21 ] = 14; // Insert interval [14, 20]
intervals[ 26 ] = 21; // Cut [14, 25] down to [21, 25]
请注意,此策略不会检查给定数字是否大于范围的下限,因此您在调用upper_bound
后手动检查。
typedef std::map< int, int > interval_set;
typedef std::pair< const int, int > interval; // {one greater than top, bottom}
bool split_interval( interval_set & s, int p ) {
interval_set::iterator it = s.upper_bound( p );
if ( p < it->second ) return false; // Interval doesn't exist. Bail out.
s.insert( interval{ p + 1, it->second } ); // Insert a new lower-part interval.
it->second = p; // Cut the lower part from the existing interval.
return true;
}