如果我理解正确,您可以进行任何类型的预处理,并且只找到不同x 的结果必须是O(log n)。如果是这样的话,在预处理后找到结果并不是什么大不了的事。 O(log n) 搜索算法确实存在。好的候选人是std::binary_search 或std::lower_bound。
一个非常幼稚的方法是准备一个包含所有缺失元素的向量,然后在上面std::lower_bound:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> input{1,2,3,5,6,10,12};
std::vector<int> missing_elements{4,7,8,9,11};
int x = 2;
auto it = std::lower_bound(missing_elements.begin(),missing_elements.end(),x);
std::cout << *it << "\n";
}
填充missing_elements 可以在O(1) 中完成。但是,10^9 大小的missing_elements 当然是不可行的。此外,这种方法对于像[1,100000000] 这样的输入非常浪费(不是时间复杂度,而是运行时和内存使用)。
Jarod42 在评论中提出的一个想法是准备一个段向量,然后在上面std::lower_bound。首先假设预处理已经完成:
#include <iostream>
#include <vector>
#include <algorithm>
int find_first_missing(const std::vector<std::pair<int,int>>& segments,int x){
std::pair<int,int> p{x,x};
auto it = std::lower_bound(segments.begin(),segments.end(),p,[](auto a,auto b){
return a.second < b.second;
});
if (it == segments.end()) return x;
if (it->first > x) return x;
return it->second+1;
}
int main() {
std::vector<int> input{1,2,3,5,6,10,12};
std::vector<std::pair<int,int>> segments{{1,3},{5,6},{10,10},{12,12}};
for (int x=0; x<13;++x) std::cout << x << " -> " << find_first_missing(segments,x) << "\n";
}
Output:
0 -> 0
1 -> 4
2 -> 4
3 -> 4
4 -> 4
5 -> 7
6 -> 7
7 -> 7
8 -> 8
9 -> 9
10 -> 11
11 -> 11
12 -> 13
因为input 已排序,segments 已排序,所以我们可以使用自定义比较器,只比较段的末尾。段向量也相对于该比较器进行排序。对lower_bound 的调用将迭代器返回到x 在内部或x 低于该段的段,因此if (it->first > x) return x; 否则我们知道it->second+1 是下一个缺失的数字。
现在只剩下创建线段向量了:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cassert>
std::vector<std::pair<int,int>> segment(const std::vector<int>& input){
std::vector<std::pair<int,int>> result;
if (input.size() == 0) return result;
int current_start = input[0];
for (int i=1;i<input.size();++i){
if (input[i-1] == input[i] || input[i-1]+1 == input[i]) continue;
result.push_back({current_start,input[i-1]});
current_start = input[i];
}
result.push_back({current_start,input.back()});
return result;
}
int main() {
std::vector<int> input{1,2,3,5,6,10,12};
std::vector<std::pair<int,int>> expected{{1,3},{5,6},{10,10},{12,12}};
auto result = segment(input);
for (const auto& e : result){
std::cout << e.first << " " << e.second << "\n";
}
assert(expected == result);
}