How do I find the above without removing the largest element and searching again? Is there a more efficient way to do this? It does not matter if the these elements are duplicates.
for (e: all elements) {
if (e > largest) {
second = largest;
largest = e;
} else if (e > second) {
second = e;
}
}
You could either initialize largest and second to an appropriate lower bound, or to the first two items in the list (check which one is bigger, and don't forget to check if the list has at least two items)
using partial_sort ?
std::partial_sort(aTest.begin(), aTest.begin() + 2, aTest.end(), Functor);
An Example:
std::vector<int> aTest;
aTest.push_back(3);
aTest.push_back(2);
aTest.push_back(4);
aTest.push_back(1);
std::partial_sort(aTest.begin(), aTest.begin()+2,aTest.end(), std::greater<int>());
int Max = aTest[0];
int SecMax = aTest[1];
nth_element(begin, begin+n,end,Compare) places the element that would be nth (where "first" is "0th") if the range [begin, end) were sorted at position begin+n and makes sure that everything from [begin,begin+n) would appear before the nth element in the sorted list. So the code you want is:
nth_element(container.begin(),
container.begin()+1,
container.end(),
appropriateCompare);
This will work well in your case, since you're only looking for the two largest. Assuming your appropriateCompare sorts things from largest to smallest, the second largest element with be at position 1 and the largest will be at position 0.
Lets assume you mean to find the two largest unique values in the list.
If the list is already sorted, then just look at the second last element (or rather, iterate from the end looking for the second last value).
If the list is unsorted, then don't bother to sort it. Sorting is at best O(n lg n). Simple linear iteration is O(n), so just loop over the elements keeping track:
v::value_type second_best = 0, best = 0;
for(v::const_iterator i=v.begin(); i!=v.end(); ++i)
if(*i > best) {
second_best = best;
best = *i;
} else if(*i > second_best) {
second_best = *i;
}
There are of course other criteria, and these could all be put into the test inside the loop. However, should you mean that two elements that both have the same largest value should be found, you have to consider what happens should three or more elements all have this largest value, or if two or more elements have the second largest.
The optimal algorithm shouldn't need more than 1.5 * N - 2 comparisons. (Once we've decided that it's O(n), what's the coefficient in front of N? 2 * N comparisons is less than optimal).
So, first determine the "winner" and the "loser" in each pair - that's 0.5 * N comparisons.
Then determine the largest element by comparing winners - that's another 0.5 * N - 1 comparisons.
Then determine the second-largest element by comparing the loser of the pair where the largest element came from against the winners of all other pairs - another 0.5 * N - 1 comparisons.
Total comparisons = 1.5 N - 2.
The answer depends if you just want the values, or also iterators pointing at the values.
Minor modification of #will answer.
v::value_type second_best = 0, best = 0;
for(v::const_iterator i=v.begin(); i!=v.end(); ++i)
{
if(*i > best)
{
second_best = best;
best = *i;
}
else if (*i > second_best)
{
second_best = *i;
}
}
Create a sublist from n..m, sort it descending. Then grab the first two elements. Delete these elements from the orginal list.
You can scan the list in one pass and save the 1st and 2nd values, that has a O(n) efficiency while sorting is O(n log n).
EDIT:
I think that partial sort is O(n log k)
Untested but fun:
template <typename T, int n>
class top_n_functor : public unary_function<T, void>
{
void operator() (const T& x) {
auto f = lower_bound(values_.begin(), values_.end(), x);
if(values_.size() < n) {
values_.insert(f, x);
return;
}
if(values_.begin() == f)
return;
auto removed = values_.begin();
values_.splice(removed, values_, removed+1, f);
*removed = x;
}
std::list<T> values() {
return values_;
}
private:
std::list<T> values_;
};
int main()
{
int A[] = {1, 4, 2, 8, 5, 7};
const int N = sizeof(A) / sizeof(int);
auto vals = for_each(A, A + N, top_n_functor<int,2>()).values();
cout << "The top is " << vals.front()
<< " with second place being " << *(vals.begin()+1) << endl;
}
If the largest is the first element, search for the second largest in [largest+1,end). Otherwise search in [begin,largest) and [largest+1,end) and take the maximum of the two. Of course, this has O(2n), so it's not optimal.
If you have random-access iterators, you could do as quick sort does and use the ever-elegant recursion:
template< typename T >
std::pair<T,T> find_two_largest(const std::pair<T,T>& lhs, const std::pair<T,T>& rhs)
{
// implementation finding the two largest of the four values left as an exercise :)
}
template< typename RAIter >
std::pair< typename std::iterator_traits<RAIter>::value_type
, typename std::iterator_traits<RAIter>::value_type >
find_two_largest(RAIter begin, RAIter end)
{
const ptr_diff_t diff = end-begin;
if( diff < 2 )
return std::make_pair(*begin, *begin);
if( diff < 3 )
return std::make_pair(*begin, *begin+1);
const RAIter middle = begin + (diff)/2;
typedef std::pair< typename std::iterator_traits<RAIter>::value_type
, typename std::iterator_traits<RAIter>::value_type >
result_t;
const result_t left = find_two_largest(begin,middle);
const result_t right = find_two_largest(middle,end);
return find_two_largest(left,right);
}
This has O(n) and shouldn't make more comparisons than NomeN's implementation.
top k is usually a bit better than n(log k)
template <class t,class ordering>
class TopK {
public:
typedef std::multiset<t,ordering,special_allocator> BEST_t;
BEST_t best;
const size_t K;
TopK(const size_t k)
: K(k){
}
const BEST_t& insert(const t& item){
if(best.size()<k){
best.insert(item);
return best;
}
//k items in multiset now
//and here is why its better - because if the distribution is random then
//this and comparison above are usually the comparisons that is done;
if(compare(*best.begin(),item){//item better than worst
erase(begin());//the worst
best.insert(item); //log k-1 average as only k-1 items in best
}
return best;
}
template <class it>
const BEST_t& insert(it i,const it last){
for(;i!=last;++i){
insert(*i);
}
return best;
}
};
Of course the special_allocator can in essence be just an array of k multiset value_types and a list of those nodes (which typically has nothing on it as the other k are in use in the multiset until its time to put a new one in and we erase and then immediate ly reuse it. Good to have this or else the memory alloc/free in std::multiset and the cache line crap kills ya. Its a (very) tiny bit of work to give it static state without violating STL allocator rules.
Not as good as a specialized algo for exactly 2 but for fixed k<<n, I would GUESS (2n+delta*n) where delta is small - my DEK ACP vol3 S&S is packed away and an estimate on delta is a bit more work that I want to do.
average worst is I would guess n(log(k-1) + 2) when in opposite order and all distinct.
best is 2n + k(log k) for the k best being the first
I think you could implement a custom array and overload the indexed get/set methods of elements. Then on every set call, compare the new value with two fields for the result. While this makes setter slower, it benefits from caching or even registers. Then its a no op to get the result. This must be faster if you populate array only once per finding maximums. But if array is modified frequently, then it is slower.
If array is used in vectorized loops, then it gets harder to implement as you have to use avx/sse optimized max methods inside setter.
Related
Given an std::vector of distinct elements sorted in ascending order, I want to develop an algorithm that determines whether there are two elements in the collection whose sum is a certain value, sum.
I've tried two different approaches with their respective trade-offs:
I can scan the whole vector and, for each element in the vector, apply binary search (std::lower_bound) on the vector for searching an element corresponding to the difference between sum and the current element. This is an O(n log n) time solution that requires no additional space.
I can traverse the whole vector and populate an std::unordered_set. Then, I scan the vector and, for each element, I look up in the std::unordered_set for the difference between sum and the current element. Since searching on a hash table runs in constant time on average, this solution runs in linear time. However, this solution requires additional linear space because of the std::unordered_set data structure.
Nevertheless, I'm looking for a solution that runs in linear time and requires no additional linear space. Any ideas? It seems that I'm forced to trade speed for space.
As the std::vector is already sorted and you can calculate the sum of a pair on the fly, you can achieve a linear time solution in the size of the vector with O(1) space.
The following is an STL-like implementation that requires no additional space and runs in linear time:
template<typename BidirIt, typename T>
bool has_pair_sum(BidirIt first, BidirIt last, T sum) {
if (first == last)
return false; // empty range
for (--last; first != last;) {
if ((*first + *last) == sum)
return true; // pair found
if ((*first + *last) > sum)
--last; // decrease pair sum
else // (*first + *last) < sum (trichotomy)
++first; // increase pair sum
}
return false;
}
The idea is to traverse the vector from both ends – front and back – in opposite directions at the same time and calculate the sum of the pair of elements while doing so.
At the very beginning, the pair consists of the elements with the lowest and the highest values, respectively. If the resulting sum is lower than sum, then advance first – the iterator pointing at the left end. Otherwise, move last – the iterator pointing at the right end – backward. This way, the resulting sum progressively approaches to sum. If both iterators end up pointing at the same element and no pair whose sum is equal to sum has been found, then there is no such a pair.
auto main() -> int {
std::vector<int> vec{1, 3, 4, 7, 11, 13, 17};
std::cout << has_pair_sum(vec.begin(), vec.end(), 2) << ' ';
std::cout << has_pair_sum(vec.begin(), vec.end(), 7) << ' ';
std::cout << has_pair_sum(vec.begin(), vec.end(), 19) << ' ';
std::cout << has_pair_sum(vec.begin(), vec.end(), 30) << '\n';
}
The output is:
0 1 0 1
Thanks to the generic nature of the function template has_pair_sum() and since it just requires bidirectional iterators, this solution works with std::list as well:
std::list<int> lst{1, 3, 4, 7, 11, 13, 17};
has_pair_sum(lst.begin(), lst.end(), 2);
I had the same idea as the one in the answer of 眠りネロク, but with a little bit more comprehensible implementation.
bool has_pair_sum(std::vector<int> v, int sum){
if(v.empty())
return false;
std::vector<int>::iterator p1 = v.begin();
std::vector<int>::iterator p2 = v.end(); // points to the End(Null-terminator), after the last element
p2--; // Now it points to the last element.
while(p1 != p2){
if(*p1 + *p2 == sum)
return true;
else if(*p1 + *p2 < sum){
p1++;
}else{
p2--;
}
}
return false;
}
well, since we are already given sorted array, we can do it with two pointer approach, we first keep a left pointer at start of the array and a right pointer at end of array, then in each iteration we check if sum of value of left pointer index and value of right pointer index is equal or not , if yes, return from here, otherwise we have to decide how to reduce the boundary, that is either increase left pointer or decrease right pointer, so we compare the temporary sum with given sum and if this temporary sum is greater than the given sum then we decide to reduce the right pointer, if we increase left pointer the temporary sum will remain same or only increase but never lesser, so we decide to reduce the right pointer so that temporary sum decrease and we reach near our given sum, similary if temporary sum is less than given sum, so no meaning of reducing the right pointer as temporary sum will either remain sum or decrease more but never increase so we increase our left pointer so our temporary sum increase and we reach near given sum, and we do the same process again and again unless we get the equal sum or left pointer index value becomes greater than right right pointer index or vice versa
below is the code for demonstration, let me know if something is not clear
bool pairSumExists(vector<int> &a, int &sum){
if(a.empty())
return false;
int len = a.size();
int left_pointer = 0 , right_pointer = len - 1;
while(left_pointer < right_pointer){
if(a[left_pointer] + a[right_pointer] == sum){
return true;
}
if(a[left_pointer] + a[right_pointer] > sum){
--right_pointer;
}
else
if(a[left_pointer] + a[right_poitner] < sum){
++left_pointer;
}
}
return false;
}
Obviously doing std::set_intersection() is a waste of time.
Isn't there a function in the algorithm header for doing exactly this?
std::find_first_of() is doing a linear search as far as I understand.
This is a solution only for std::set (or multi). A solution for map would require only a bit more work.
I try it 3 ways.
First, if one is far larger than the other, I simply look for all of the elements of one in the other. Then vice versa.
The constant 100 is wrong theoretically. It should be k n lg m > m for some k, not 100 n > m for optimal big-O performance: but the constant factor is large, and 100>lg m, so really one should experiment.
If that isn't the case, we walk through each collection looking for collisions much like set_intersection. Instead of just ++, we use .lower_bound to try to skip through each list faster.
Note that if your list consists of interleaved elements (like {1,3,7} and {0,2,4,6,8}) this will be slower than just ++ by a logarithmic factor.
If the two sets "cross" each other less often, this can skip over large amounts of each set's contents.
Replace the lower_bound portion with a mere ++ if you want to compare the two behaviors.
template<class Lhs, class Rhs>
bool sorted_has_overlap( Lhs const& lhs, Rhs const& rhs ) {
if (lhs.empty() || rhs.empty()) return false;
if (lhs.size() * 100 < rhs.size()) {
for (auto&& x:lhs)
if (rhs.find(x)!=rhs.end())
return true;
return false;
}
if (rhs.size() * 100 < lhs.size()) {
for(auto&& x:rhs)
if (lhs.find(x)!=lhs.end())
return true;
return false;
}
using std::begin; using std::end;
auto lit = begin(lhs);
auto lend = end(lhs);
auto rit = begin(rhs);
auto rend = end(rhs);
while( lit != lend && rit != rend ) {
if (*lit < *rit) {
lit = lhs.lower_bound(*rit);
continue;
}
if (*rit < *lit) {
rit = rhs.lower_bound(*lit);
continue;
}
return true;
}
return false;
}
a sorted array could do the 3rd choice of algorithm and use std::lower_bound to do fast advance of the "other" container. This has the advantage of using partial searches (which you cannot do fast in a set). It will also behave poorly on "interleaved" elements (by a log n factor) compared to naive ++.
The first two can also be done fast with sorted arrays, replacing method calls with calls to algorithms in std. Such a transformation is basically mechanical.
An asymptotically optimal version on a sorted array would use a binary search biased towards finding lower bounds at the start of the list -- search at 1, 2, 4, 8, etc instead of at half, quarters, etc. Note that this has the same lg(n) worst case, but is O(1) if the searched for element is first instead of O(lg(n)). As that case (where the search advances less) means less global progress is made, optimizing the sub-algorithm for that case gives you a better global worst-case speed.
To get why, on "fast alternation" it wouldn't perform any worse than ++ -- the case where the next element is a sign swap takes O(1) operations, and it replaces O(k) with O(lg k) if the gap is larger.
However, by this point we are far, far down an optimization hole: profile, and determine if it is worth it before proceeding this way.
Another approach on sorted arrays is to presume that std::lower_bound is written optimally (on random access iterators). Use an output iterator that throws an exception if written to. Return true iff you catch that exception, false otherwise.
(the optimizations above -- pick one and bin search the other, and exponential advance searching -- may be legal for a std::set_intersection.)
I think the use of 3 algorithms is important. Set intersection testing where one side is much smaller that the other is probably common: the extreme case of one element on one side, and many on the other is very well known (as a search).
A naive 'double linear' search gives you up to linear performance in that common case. By detecting the assymmetry between sides, you can switch over to 'linear in small, log in large' at an opportune point, and have the much better performance in those cases. O(n+m) vs O(m lg n) -- if m < O(n/lg n) the second beats the first. If m is a constant, then we get O(n) vs O(lg n) -- which includes the edge case of 'use function to find if a single element is in some large collection'.
You can use the following template function if the inputs are sorted:
template<class InputIt1, class InputIt2>
bool intersect(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2)
{
while (first1 != last1 && first2 != last2) {
if (*first1 < *first2) {
++first1;
continue;
}
if (*first2 < *first1) {
++first2;
continue;
}
return true;
}
return false;
}
You can use like this:
#include <iostream>
int main() {
int a[] = {1, 2, 3};
int b[] = {3, 4};
int c[] = {4};
std::cout << intersect(a, a + 3, b, b + 2) << std::endl;
std::cout << intersect(b, b + 2, c, c + 1) << std::endl;
std::cout << intersect(a, a + 3, c, c + 1) << std::endl;
}
Result:
1
1
0
This function has complexity O(n + m) where n, m are input sizes. But if one input is very small to the other (n << m for example), it's better to check each of the n elements with binary search if it belongs to the other input. This gives O(n * log(m)) time.
#include <algorithm>
template<class InputIt1, class InputIt2>
/**
* When input1 is much smaller that input2
*/
bool intersect(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) {
while (first1 != last1)
if (std::binary_search(first2, last2, *first1++))
return true;
return false;
}
Sometimes you can encode sets of numbers in a single memory word. For example, you could encode the set {0,2,3,6,7} in the memory word: ...00000011001101. The rule is: the bit at position i (reading from right to left) is up, if and only if the number i is in the set.
Now if you have two sets, encoded in the memory words a and b, you can perform the intersection using the bitwise operator &.
int a = ...;
int b = ...;
int intersection = a & b;
int union = a | b; // bonus
The good thing of this style, is that the intersection ( union, complementation ) is performed in one cpu instruction (I don't know if this is the correct term).
You could use more than one memory word, if you need to handle numbers that are greater than the number of bits of a memory word. Normally, I use an array of memory words.
If you want handle negative numbers, just use two arrays, one for negative numbers, and one for positive numbers.
The bad thing of this method, is that it works only with integers.
I think you can make a binary_search
#include <set>
#include <iostream>
#include <algorithm>
bool overlap(const std::set<int>& s1, const std::set<int>& s2)
{
for( const auto& i : s1) {
if(std::binary_search(s2.begin(), s2.end(), i))
return true;
}
return false;
}
int main()
{
std::set<int> s1 {1, 2, 3};
std::set<int> s2 {3, 4, 5, 6};
std::cout << overlap(s1, s2) << '\n';
}
How to find the maximum and minimum value in an array without using if statement.Are there any built in function in to do so in c++? If not is insertion sort the only way?Thanks in advance.
Use std::minmax_element if you use C++11, or std::min_element/std::max_element if no.
std::vector<int> v = {1,2,3,4};
auto minmax = std::minmax_element(v.begin(), v.end());
// now minmax.first points on 1 and minmax.second points on 4
However, if if condition should not be used internally - you can use following thing
template<typename Iterator>
std::pair<Iterator, Iterator> minmax_element(Iterator first, Iterator last)
{
Iterator min = first, max = first;
while (first != last)
{
min = *min > *first ? first : min;
max = *max > *first ? max : first;
++first;
}
return std::make_pair(min, max);
}
First of all, you can implement function sort(a, b), which returns pair of sorted values. To do it you can use following idea: min(a, b) = (a+b)/2 - |a-b|/2 and max(a, b) = (a+b)/2 + |a-b|/2.
But here you have function |x|=abs(x), which uses 'if' inside. So, we should implement 'abs' without any 'if'. One of the simpliest ways is following: abs(x) = sqrt(x*x) (it is very slow, but it is only an idea). For integer values you can use these approaches: 1, 2, etc.
So, you can implement function sort(a,b) which sorts only pair of values without any 'if'. After it you can use this function to sort the array. After it first element of that sorted array will be minimum value and last element will be maximum element.
I have two vectors, each contains n unsorted elements, how can I get n largest elements in these two vectors?
my solution is merge two vector into one with 2n elements, and then use std::nth_element algorithm, but I found that's not quite efficient, so anyone has more efficient solution. Really appreciate.
You may push the elements into priority_queue and then pop n elements out.
Assuming that n is far smaller than N this is quite efficient. Getting minElem is cheap and sorted inserting in L cheaper than sorting of the two vectors if n << N.
L := SortedList()
For Each element in any of the vectors do
{
minElem := smallest element in L
if( element >= minElem or if size of L < n)
{
add element to L
if( size of L > n )
{
remove smallest element from L
}
}
}
vector<T> heap;
heap.reserve(n + 1);
vector<T>::iterator left = leftVec.begin(), right = rightVec.begin();
for (int i = 0; i < n; i++) {
if (left != leftVec.end()) heap.push_back(*left++);
else if (right != rightVec.end()) heap.push_back(*right++);
}
if (left == leftVec.end() && right == rightVec.end()) return heap;
make_heap(heap.begin(), heap.end(), greater<T>());
while (left != leftVec.end()) {
heap.push_back(*left++);
push_heap(heap.begin(), heap.end(), greater<T>());
pop_heap(heap.begin(), heap.end(), greater<T>());
heap.pop_back();
}
/* ... repeat for right ... */
return heap;
Note I use *_heap directly rather than priority_queue because priority_queue does not provide access to its underlying data structure. This is O(N log n), slightly better than the naive O(N log N) method if n << N.
You can do the "n'th element" algorithm conceptually in parallel on the two vectors quite easiely (at least the simple variant that's only linear in the average case).
Pick a pivot.
Partition (std::partition) both vectors by that pivot. You'll have the first vector partitioned by some element with rank i and the second by some element with rank j. I'm assuming descending order here.
If i+j < n, recurse on the right side for the n-i-j greatest elements. If i+j > n, recurse on the left side for the n greatest elements. If you hit i+j==n, stop the recursion.
You basically just need to make sure to partition both vectors by the same pivot in every step. Given a decent pivot selection, this algorithm is linear in the average case (and works in-place).
See also: http://en.wikipedia.org/wiki/Selection_algorithm#Partition-based_general_selection_algorithm
Edit: (hopefully) clarified the algorithm a bit.
I have a std::vector containing a handful of numbers, which are not in any particular order, and may or may not have gaps between the numbers - for example, I may have { 1,2,3, 6 } or { 2,8,4,6 } or { 1, 9, 5, 2 }, etc.
I'd like a simple way to look at this vector and say 'give me the lowest number >= 1 which does not appear in the vector'. So,
for the three examples above, the answers would be 4, 1 and 3 respectively.
It's not performance critical, and the list is short so there aren't any issues about copying the list and sorting it, for example.
I am not really stuck for a way to do this, but my STL skills are seriously atrophied and I can feel that I'm about to do something inelegant - I would be interested to see what other people came up with.
The standard algorithm you are looking for is std::adjacent_find.
Here is a solution that also uses a lambda to make the predicate clean:
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;
}
The checked answer uses < for comparison. != is much simpler:
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
I'm not passing a reference to the vector since a) he said time doesn't matter and b) so I don't change the order of the original vector.
Sorting the list and then doing a linear search seems the simplest solution. Depending on the expected composition of the lists you could use a less general purpose sorting algorithm, and if you implement the sort yourself you could keep track of data during the sort that could be used to speed up (or eliminate entirely) the search step. I do not think there is any particularly elegant solution to this problem
You could allocate a bit vector (of the same length as the input vector), initialize it to zero, then mark all indices that occur (note that numbers larger than the length can be ignored). Then, return the first unmarked index (or the length if all indices are marked, which only happens if all indices occur exactly once in the input vector).
This should be asymptotically faster than sort and search. It will use more memory than sorting if you are allowed to destroy the original, but less memory than sorting if you must preserve the original.
Actually, if you do a bubble sort (you know... the one that they teach you first and then tell you to never use again...), you will be able to spot the first gap early in the sorting process, so you can stop there. That should give you the fastest overall time.
Sort-n-search:
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;
Iterators could be used with just as clear intent as showcased in #joe_mucchiello's (ed: better) answer.
OK, here's my 2 cents. Assume you've got a vector of length N.
If N<=2 you can check directly
First, use min_element to get the smallest element, remember it as emin
Call nth_element to get the element at N/2, call it ehalf
If ehalf != emin+N/2 there's a gap to the left, apply this method recursively there by calling nth_element on the whole array but asking for element N/4. Otherwise, recurse on the right asking for element 3*N/4.
This should be slightly better than sorting completely up front.
you could go with something like....
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());
}
A possible implementation of Thomas Kammeyer's answer
I found Thomas' approach really smart and useful - since some of us dream in code and I find the actual implementation a bit tricky I wanted to provide some ready-to-use code.
The solution presented here is as generic as possible:
No assumption is made on the type of container or range except their iterators must meet the requirements of ValueSwappable and RandomAccessIterator (due to partial sorting with nth_element)
Any number type can be used - the required traits are outlined below
Another improvement I think is that a no-gap condition can be checked early: since we have to scan for the minimum anyway we can also scan for the maximum at the same time and then determine whether the number range even contains a gap worth finding.
Last but not least the same recursive approach can be adapted for sorted ranges! If you encode in a template value parameter whether the range is already sorted, you can simply skip the partial sorting plus make determining minimum/maximum elements a no-op.
#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;
}