在集合或列表中按顺序查找缺失的数字

时间:2010-06-16 16:48:32

标签: c++ list stl set

如果std::setstd::list包含一系列自然数(1,2,3 ......)。标准库中是否有一个函数可以找到丢失的数字?

3 个答案:

答案 0 :(得分:6)

你可以std::mismatch()使用一系列自然数。为了节省空间,我认为boost::counting_iterator可以在这里创造奇迹:

#include <iostream>
#include <list>
#include <boost/iterator/counting_iterator.hpp>
int main()
{
    std::list<int> l = {1,2,3,4,6,7,8,9};
    auto i = mismatch(l.begin(), l.end(), boost::counting_iterator<int>(1));
    if(i.first==l.end())
            std::cout << "no missing numbers\n";
    else
            std::cout << "the first missing number is " << *i.second << '\n';

}

试运行:

~ $ g++ -std=c++0x -pedantic -Wall -Wextra -o test test.cc
~ $ ./test
the first missing number is 5

答案 1 :(得分:4)

您可以使用set_difference和自定义迭代器找到所有缺失的数字:

class seqIter : public std::iterator<std::input_iterator_tag, int> {
public:
    seqIter(int n) : num(n) {}
    seqIter(const seqIter & n) : num(n.num) {}
    int & operator *() {return num;}
    seqIter & operator ++() { ++num; return *this; }
    bool operator !=(const seqIter & n) { return n.num != num; }
private:
    int num;
};

int main(int argc, char *argv[])
{
    int n[] = { 1, 3, 4, 7, 10 };
    std::set<int>   numbers(n, n + sizeof(n)/sizeof(n[0]));
    std::set<int>   missing;
    std::set_difference(    seqIter(*numbers.begin()+1), seqIter(*numbers.rbegin()), 
                            numbers.begin(), numbers.end(),
                            std::insert_iterator<std::set<int> >(missing, missing.begin())
                        );
}

这可能不比通过for循环通过数字更快。

答案 2 :(得分:3)

没有专门用于此目的(标准算法试图更加概括)。但是,您可以使用std::accumulate作为相当大的一部分工作。

提示:1..N中一组数字的总和为(N + 1)*(N / 2)。

编辑:我对答案的想法是,如果所有数字都存在,则从你得到的总和中减去你所拥有数字的总和。这种差异将是缺失的数字。

#include <numeric>
#include <iostream>

#define elements(x) (sizeof(x)/sizeof(x[0]))

int main() { 
    int x[] = {8, 4, 3, 5, 1, 2, 7}; 


    int N = elements(x) +1;

    int projected_sum = (N+1)*(N/2);
    int actual_sum = std::accumulate(x, x+elements(x), 0);

    std::cout << "The missing number is: " << projected_sum - actual_sum << "\n";
    return 0;
}

目前,这忽略了一些细微的细节,例如如果集合具有奇数个元素会发生什么,但应该显示一般的想法。我还使用了数组而不是列表,只是为了便于初始化。我没有使用列表不能(合理地)支持的随机访问。这具有线性复杂性,正如您从示例输入中看到的那样,不需要对输入进行排序。

Edit2:如果意图是输入按排序顺序,我可能会稍微改变一下这个工作:只需走过去找一个不比它的前任更大的项目。