查找向量中缺少的第一个元素 这个问题,但我找不到C++。< /P>

查找向量中缺少的第一个元素 这个问题,但我找不到C++。< /P>,c++,algorithm,vector,counting,missing-data,C++,Algorithm,Vector,Counting,Missing Data,如果我有一个向量和一个起始数字,std::algorithm是否为我提供了一种查找下一个最高缺失数字的方法 很明显,我可以用嵌套的循环来写这篇文章,我无法摆脱我正在重新发明轮子的感觉 例如,给定:向量foo{13,8,3,6,10,1,7,0} 起始编号0应为2 起始编号6应为9 起始编号-2应为-1 编辑: 到目前为止,所有的解决方案都需要排序。实际上,这可能是必需的,但必须创建一个临时排序的向量来适应这一点,因为foo必须保持不变。第一种解决方案: 对向量进行排序。找到起始号码,看看下一个号

如果我有一个向量和一个起始数字,std::algorithm是否为我提供了一种查找下一个最高缺失数字的方法

很明显,我可以用嵌套的循环来写这篇文章,我无法摆脱我正在重新发明轮子的感觉

例如,给定:
向量foo{13,8,3,6,10,1,7,0}

起始编号
0
应为
2

起始编号
6
应为
9

起始编号
-2
应为
-1

编辑:

到目前为止,所有的解决方案都需要排序。实际上,这可能是必需的,但必须创建一个临时排序的
向量来适应这一点,因为
foo
必须保持不变。

第一种解决方案:

对向量进行排序。找到起始号码,看看下一个号码是什么。 这将取O(NlogN),其中N是向量的大小

第二种解决方案:

如果数字范围很小,例如(0,M),则可以创建大小为M的布尔向量。对于每个初始向量数,使该索引的布尔值为真。稍后,通过检查布尔向量,您可以看到下一个缺失的数字。这将需要O(N)时间和O(M)辅助存储器。

  • 首先需要对向量进行排序。用这个

  • 查找与给定元素大于或等于的第一个元素。(元素必须至少部分有序)

  • 从那里,您可以在拥有连续元素的同时进行迭代

  • <重复>处理重复:一种方法是:我在迭代时考虑连续的和相等的元素。另一种方法是添加一个先决条件,即向量/范围包含唯一的元素。我选择前者是因为它可以避免删除元素

以下是如何从已排序向量中消除重复项:

v.erase(std::unique(v.begin(), v.end()), v.end());
我的实施:

// finds the first missing element in the vector v
// prerequisite: v must be sorted
auto firstMissing(std::vector<int> const &v, int elem) -> int {
  auto low = std::lower_bound(std::begin(v), std::end(v), elem);

  if (low == std::end(v) || *low != elem) {
    return elem;
  }

  while (low + 1 != std::end(v) &&
         (*low == *(low + 1) || *low + 1 == *(low + 1))) {
    ++low;
  }
  return *low + 1;
}

关于排序的说明:从OP的评论中,他正在寻找一种不会修改向量的解决方案

您必须对向量进行排序,以获得有效的解决方案。如果修改向量不是一个选项,您可以创建一个副本并处理它

如果您执意不进行排序,那么有一种蛮力解决方案(非常低效-O(n^2)):


至少就我所知,没有一种标准的算法可以直接实现你所要求的


如果您想用O(nlogn)这样的复杂度来完成它,您可以从对输入进行排序开始。然后使用
std::upper_bound
查找您请求的号码(如果存在)的(最后一个实例)。从那里,你会发现一个数字与前一个数字相差不止一个。从那里,您可以扫描集合中连续数字之间大于1的差值

在实际代码中执行此操作的一种方法如下:

#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
#include <iterator>

int find_missing(std::vector<int> x, int number) {
    std::sort(x.begin(), x.end());
    auto pos = std::upper_bound(x.begin(), x.end(), number);

    if (*pos - number > 1)
        return number + 1;
    else {
        std::vector<int> diffs;
        std::adjacent_difference(pos, x.end(), std::back_inserter(diffs));
        auto pos2 = std::find_if(diffs.begin() + 1, diffs.end(), [](int x) { return x > 1; });
        return *(pos + (pos2 - diffs.begin() - 1)) + 1;
    }
}

int main() {
    std::vector<int> x{ 13, 8, 3, 6, 10, 1,7, 0};

    std::cout << find_missing(x, 0) << "\n";
    std::cout << find_missing(x, 6) << "\n";
}
#包括
#包括
#包括
#包括
#包括
int find_缺失(std::vector x,int number){
std::sort(x.begin(),x.end());
auto pos=std::上限(x.begin(),x.end(),number);
如果(*位置-编号>1)
返回号码+1;
否则{
std::向量差异;
标准::相邻插入器差异(位置,x.end(),标准::后插入器(差异));
auto pos2=std::find_if(diffs.begin()+1,diffs.end(),[](int x){return x>1;});
返回*(pos+(pos2-diff.begin()-1))+1;
}
}
int main(){
std::向量x{13,8,3,6,10,1,7,0};

std::cout所以我想我应该发布一个答案。我不知道std::算法中有什么可以直接实现这一点,但是结合
向量
可以在O(2N)中实现

模板
T发现_缺失(常量向量&v,T元素){
向量范围(v.size());
elem++;
对于每个(v.begin()、v.end()、[&](const T&i){if((i>=elem&&i-elem
我认为OP是在寻找更具体的惯用C++-ish,而不是可以使用的基本算法的一般描述。(但是,+1.即使可能,也不是所有东西都能从STL化中受益。)顺便说一下,通过忽略[x+1,x+N]范围之外的值,可以调整第二种方法,使其在M不小的情况下也能工作。是的,辅助内存将是O(N)而不是O(M)@但我的问题是我不能对向量进行排序,否则我只需要维护一个已排序的向量并执行此操作:我当前的解决方案是维护一个
向量
。这可能会很好:(在我看来,
上限
在这里比
下限
更有意义。如果请求的数字有多个实例,你会想要最后一个,而不是第一个。@JerryCoffin我考虑过这一点,但是使用上限你无法判断你的元素是否在范围内。如果不是,那么元素就是第一个丢失的。看起来类似于
if(*result==input\u number)
是一种非常简单的方法,可以确定返回的迭代器是否引用了较高数字的输入数字。还要注意,如果数字不存在,
下限
上限
都将返回完全相同的结果(一个迭代器,用于下一个比请求的项更大的项)。@JerryCoffin是的。但是如果容器中有重复项,alg将失败得很惨,无论上界的下界是什么。(将发现第一个重复项作为第一个丢失的项)将进行编辑。@bolov感谢您的解决方案!从所有的答案来看,似乎处理此问题的唯一方法是对
向量进行排序,这让我很难过,但事实就是如此。
std::upper_bound
很有趣。但我认为比较函数不能调整到足以使其在未排序的容器上工作。我真正喜欢的是什么如果没有这样的话,它是可以工作的
int main() {
  auto v = std::vector<int>{13, 8, 3, 6, 10, 1, 7, 7, 7, 0};    
  std::sort(v.begin(), v.end());

  for (auto n : {-2, 0, 5, 6, 20}) {
    cout << n << ": " << firstMissing(v, n) << endl;
  }

  return 0;
}
-2: -2  
0: 2  
5: 5  
6: 9  
20: 20  
auto max = std::max_element(std::begin(v), std::end(v));
if (elem > *max) {
  return elem;
}
auto i = elem;
while (std::find(std::begin(v), std::end(v), i) != std::end(v)) {
  ++i;
}
return i;
#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
#include <iterator>

int find_missing(std::vector<int> x, int number) {
    std::sort(x.begin(), x.end());
    auto pos = std::upper_bound(x.begin(), x.end(), number);

    if (*pos - number > 1)
        return number + 1;
    else {
        std::vector<int> diffs;
        std::adjacent_difference(pos, x.end(), std::back_inserter(diffs));
        auto pos2 = std::find_if(diffs.begin() + 1, diffs.end(), [](int x) { return x > 1; });
        return *(pos + (pos2 - diffs.begin() - 1)) + 1;
    }
}

int main() {
    std::vector<int> x{ 13, 8, 3, 6, 10, 1,7, 0};

    std::cout << find_missing(x, 0) << "\n";
    std::cout << find_missing(x, 6) << "\n";
}
template <typename T>
T find_missing(const vector<T>& v, T elem){
    vector<bool> range(v.size());
    elem++;

    for_each(v.begin(), v.end(), [&](const T& i){if((i >= elem && i - elem < range.size())range[i - elem] = true;});

    auto result = distance(range.begin(), find(range.begin(), range.end(), false));

    return result + elem;
}