如何以STL方式查找列表中的最小缺失整数

时间:2015-10-25 12:09:11

标签: c++ algorithm stl

我想找到给定列表中的最小缺失正整数。也就是说,如果给出一个正整数列表,即重复大于0,如何找到那些缺少最小的整数。

序列中始终至少有一个缺失的元素。

例如给定

std::vector<int> S={9,2,1,10};

答案应该是3,因为缺失的整数是3,4,5,6,7,8,11,...而且最小值是3。

我想出了这个:

int min_missing( std::vector<int> & S)
{
  int max = std::max_element(S.begin(), S.end());
  int min = std::min_element(S.begin(), S.end());
  int i = min;
  for(; i!=max and std::find(S.begin(), S.end(), i) != S.end() ; ++i);
  return i;
}

这是O(nmlogn)的时间,但我无法弄清楚是否有更高效的C ++ STL方法来做到这一点?

这不是一个练习,但我正在为自我提升做一系列问题,我发现这是一个非常有趣的问题。我很想知道如何改进这一点。

5 个答案:

答案 0 :(得分:1)

您可以使用std::sort,然后将std::adjacent_find与自定义谓词一起使用。

int f(std::vector<int>  v)
{
    std::sort(v.begin(), v.end());
    auto i = std::adjacent_find( v.begin(), v.end(), [](int x, int y) 
    {
        return y != x+1;
    } );

    if (i != v.end())
    {
         return *i + 1;
    }
}

当没有这样的元素存在时会发生什么,例如当向量为空时。

答案 1 :(得分:0)

您可以使用算法将标准模板库c ++用于您的代码。

#include <algorithm>    // std::sort

算法中的std::sort

std::vector<int> v={9,2,5,1,3};

std::sort(v.begin(),v.end());

std::cout << v[0];

我希望我明白你的意思。

答案 2 :(得分:0)

找到第一个缺失的阳性,有O(n)时间和恒定空间

基本上,当你读取一个值a时,只需用S [a]交换,就像2应交换为A [2]

class Solution {
public:
/**    
 * @param A: a vector of integers
 * @return: an integer
 */
int firstMissingPositive(vector<int> A) {
    // write your code here
    int n = A.size();
    for(int i=0;i<n;)
    {
        if(A[i]==i+1)
            i++;
        else
        {
            if(A[i]>=1&&A[i]<=n&& A[A[i]-1]!=A[i])
                swap(A[i],A[A[i]-1]);
            else
                i++;
        }
    }
    for(int i=0;i<n;i++)
        if(A[i]!=i+1)
            return i+1;
    return n+1;
   }
};

答案 3 :(得分:0)

假设数据先排序:

    auto missing_data = std::mismatch(S.cbegin(), S.cend()-1, S.cbegin() + 1,
                                      [](int x, int y) { return (x+1) == y;});

修改 由于您的输入数据未排序,最简单的解决方案是首先对它们进行排序:

   std::vector<int> data(S.size());
   std::partial_sort_copy (S.cbegin(), S.cend(), data.begin(), data.end());
   auto missing_data = std::mismatch (data.cbegin(), data.cend()-1, data.cbegin()+1,
                                      [](int x, int y) { return (x+1) == y;});

答案 4 :(得分:-1)

你可以通过构建一组整数并在集合中添加更大的整数来实现这一点,并保持最小值不作为计数器。一旦有一个等于后者的数字,请通过set删除元素,直到缺少整数。

请参阅下面的实施。

template<typename I> typename I::value_type solver(I b, I e)
{
    constexpr typename I::value_type maxseen=
      std::numeric_limits<typename I::value_type>::max();
    std::set<typename I::value_type> seen{maxseen};

    typename I::value_type minnotseen(1);

    for(I p=b; p!=e;++p)
    {
        if(*p == minnotseen)
        {
            while(++minnotseen == *seen.begin())
            {
                seen.erase(seen.begin());
            }

        } else if( *p > minnotseen)
        {
            seen.insert(*p);
        }
    }

    return minnotseen;
}

如果你的序列在一个向量中,你应该使用它:

solver(sequence.begin(),sequence.end());

该算法在时间上是O(N),在空间中是O(1),因为它只使用计数器,恒定大小的附加空间和一些迭代器来跟踪最小值。

复杂性(增长率的顺序)该算法仅保留输入的子集,该输入预期相对于输入的增长率具有恒定的增长顺序,因此在空间中为O(1)。迭代的增长率是O(N + NlogK),其中K是所见较大数字的较大子序列的增长率。后者是上述恒定增长率的子序列,即K = 1,这导致算法具有O(N)复杂度。(见注释)