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

How to find the minimal missing integer in a list in an STL way

本文关键字:整数 列表 STL 方式      更新时间:2023-10-16

我想在给定的列表中找到最小缺失的正整数。也就是说,如果给定一个正整数列表,即大于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的方式来做到这一点?

这不是练习,而是我在做一组自我完善的问题,我发现这是一个非常有趣的问题。

您可以使用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;
    }
}

当不存在这样的元素时,例如当vector为空时,则保持开放

用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;
   }
};

假设数据先排序:

    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;});

你可以使用标准模板库c++的算法在你的代码中工作。

#include <algorithm>    // std::sort

this std::sort in algorithm:

std::vector<int> v={9,2,5,1,3};
std::sort(v.begin(),v.end());
std::cout << v[0];

我希望我明白你在看什么

您可以通过构建一组整数并将集合中看到的较大的整数相加,并将未看到的最小值保留为计数器来实现此目的。一旦有一个数字等于后者,遍历删除元素集合,直到有一个缺失的整数。

具体操作请参见下文。

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)。(见注释)