我有一个包含少数数字的std :: vector,这些数字没有任何特定的顺序,数字之间可能有差距,也可能没有差距 - 例如,我可能有{1,2,3,6}或{2,8,4,6}或{1,9,5,2}等
我想要一个简单的方法来查看这个向量并说“给我最小的数字> = 1,不出现在向量中”。所以,
对于上面三个例子,答案分别为4,1和3。
这不是性能关键,而且列表很短,所以没有任何关于复制列表和排序的问题,例如。
我并没有真正坚持这样做的方法,但我的STL技能严重萎缩,我觉得我要做一些不优雅的事情 - 我会有兴趣看看其他人想出的。< / p>
答案 0 :(得分:12)
您要查找的标准算法是 std::adjacent_find 。
这是一个解决方案,它也使用lambda来使谓词干净:
int first_gap( std::vector<int> vec )
{
// Handle the special case of an empty vector. Return 1.
if( vec.empty() )
return 1;
// Sort the vector
std::sort( vec.begin(), vec.end() );
// Find the first adjacent pair that differ by more than 1.
auto i = std::adjacent_find( vec.begin(), vec.end(), [](int l, int r){return l+1<r;} );
// Handle the special case of no gaps. Return the last value + 1.
if ( i == vec.end() )
--i;
return 1 + *i;
}
答案 1 :(得分:10)
选中的答案使用&lt;为了比较。 !=更简单:
int find_gap(std::vector<int> vec) {
std::sort(vec.begin(), vec.end());
int next = 1;
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
if (*it != next) return next;
++next;
}
return next;
}
find_gap(1,2,4,5) = 3
find_gap(2) = 1
find_gap(1,2,3) = 4
我没有传递对向量的引用,因为a)他说时间无关紧要b)所以我不改变原始向量的顺序。
答案 2 :(得分:4)
对列表进行排序然后进行线性搜索似乎是最简单的解决方案。根据列表的预期组成,您可以使用较少通用的排序算法,如果您自己实现排序,则可以在排序期间跟踪数据,以便加速(或完全消除)搜索步骤。我不认为这个问题有任何特别优雅的解决方案
答案 3 :(得分:4)
您可以分配一个位向量(与输入向量长度相同),将其初始化为零,然后标记出现的所有索引(请注意,可以忽略大于长度的数字)。然后,返回第一个未标记的索引(如果所有索引都被标记,则返回长度,只有当所有索引在输入向量中只出现一次时才会发生。)
这应该比排序和搜索渐近快。如果允许销毁原始文件,它将使用比排序更多的内存,但如果必须保留原始文件,则会比排序更少的内存。
答案 4 :(得分:2)
排序正搜索:
std::sort(vec.begin(), vec.end());
int lowest = 1;
for(size_t ii = 1; ii < vec.size(); ++ii)
{
if (vec[ii - 1] + 1 < vec[ii])
{
lowest = (vec[ii - 1] + 1);
break;
}
}
/* 1, 2, ..., N case */
if (lowest == vec[0]) lowest = (*vec.back()) + 1;
迭代器的使用方式与showcased in @joe_mucchiello's (ed: better) answer一样明确。
答案 5 :(得分:2)
实际上,如果你进行冒泡排序(你知道......他们先教你的那个,然后告诉你再也不用了......),你就能在排序的早期发现第一个缺口过程,所以你可以停在那里。这应该会给你最快的整体时间。
答案 6 :(得分:1)
好的,这是我的2美分。假设你有一个长度为N的向量。
这应该比预先完全排序要好一些。
答案 7 :(得分:1)
你可以选择类似......
struct InSequence
{
int _current; bool insequence;
InSequence() : _current(1), insequence(true){}
bool operator()(int x) {
insequence = insequence ? (x == _current) : false;
_current++;
return insequence;
}
};
int first_not_in_sequence(std::vector<int>& v)
{
std::sort(v.begin(), v.end());
return 1+std::count_if(v.begin(), v.end(),InSequence());
}
答案 8 :(得分:0)
Thomas Kammeyer答案的可能实施
我发现托马斯的方法非常聪明和有用 - 因为我们中的一些人梦想着代码,我发现实际的实现有点棘手,我想提供一些现成的代码。
此处介绍的解决方案尽可能通用:
nth_element
进行部分排序)我认为另一个改进是可以提前检查无间隙条件:因为我们必须扫描最小值,我们也可以同时扫描最大值,然后确定数字范围是否包含间隙值得一试。
最后但并非最不重要的是,相同的递归方法可以适用于排序范围!如果您在模板值参数中编码该范围是否已经排序,您可以简单地跳过部分排序加上确定最小/最大元素为无操作。
#include <type_traits>
#include <iterator>
#include <tuple>
#include <utility>
#include <algorithm>
#include <cstddef>
// number type must be:
// * arithmetic
// * subtractable (a - b)
// * divisible by 2 (a / 2)
// * incrementable (++a)
// * less-than-comparable (a < b)
// * default-constructible (A{})
// * copy-constructible
// * value-constructible (A(n))
// * unsigned or number range must only contain values >0
/** Find lowest gap value in a range */
template<typename Range>
typename std::remove_reference_t<Range>::value_type
lowest_gap_value_unsorted(Range&& r)
{
static_assert(!std::is_lvalue_reference_v<Range> && !std::is_const_v<Range>, "lowest_gap_value_unsorted requires a modifiable copy of the passed range");
return lowest_gap_value_unsorted(std::begin(r), std::end(r), std::size(r));
}
/** Find lowest gap value in a range with specified size */
template<typename Range>
typename std::remove_reference_t<Range>::value_type
lowest_gap_value_unsorted(Range&& r, std::size_t N)
{
static_assert(!std::is_lvalue_reference_v<Range> && !std::is_const_v<Range>, "lowest_gap_value_unsorted requires a modifiable copy of the passed range");
return lowest_gap_value_unsorted(std::begin(r), std::end(r), N);
}
/** Find lowest gap value in an iterator range */
template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type
lowest_gap_value_unsorted(Iterator first, Iterator last)
{
return lowest_gap_value_unsorted(first, last, std::distance(first, last));
}
/** Find lowest gap value in an iterator range with specified size */
template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type
lowest_gap_value(Iterator first, Iterator last, std::size_t N)
{
typedef typename std::iterator_traits<Iterator>::value_type Number;
if (bool empty = last == first)
return increment(Number{});
Iterator minElem, maxElem;
std::tie(minElem, maxElem) = std::minmax_element(first, last);
if (bool contains0 = !(Number{} < *minElem))
throw std::logic_error("Number range must not contain 0");
if (bool missing1st = increment(Number{}) < *minElem)
return increment(Number{});
if (bool containsNoGap = !(Number(N) < increment(*maxElem - *minElem)))
return increment(*maxElem);
return lowest_gap_value_unsorted_recursive(first, last, N, *minElem);
}
template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type
lowest_gap_value_unsorted_recursive(Iterator first, Iterator last, std::size_t N, typename std::iterator_traits<Iterator>::value_type minValue)
{
typedef typename std::iterator_traits<Iterator>::value_type Number;
if (N == 1)
return ++minValue;
if (N == 2)
{
// determine greater of the 2 remaining elements
Number maxValue = !(minValue < *first) ? *std::next(first) : *first;
if (bool gap = ++minValue < maxValue)
return minValue;
else
return ++maxValue;
}
Iterator medianElem = std::next(first, N / 2);
// sort partially
std::nth_element(first, medianElem, last);
if (bool gapInLowerHalf = (Number(N) / 2 < *medianElem - minValue))
return lowest_gap_value_unsorted_recursive(first, medianElem, N / 2, minValue);
else
return lowest_gap_value_unsorted_recursive(medianElem, last, N / 2 + N % 2, *medianElem);
};
template<typename T>
T increment(T v)
{
return ++v;
}