So I really struggled with this and even now I am not happy with my solution.
I have a set
that at least contains 0, and may contain other positive int
s. I need to find the first positive number not in the set
.
So writing a standard while
-loop to accomplish this is easy.
i = foo.begin();
while (i != prev(foo.end()) && *i + 1 == *next(i)){
++i;
}
cout << "First number that cannot be formed " << *i + 1 << endl;
But when I try to write an STL algorithm version of the loop I get something that fails like this loop:
auto i = foo.begin();
while (++i != prev(foo.end()) && *prev(i) + 1 == *i);
cout << "First number that cannot be formed " << *prev(i) + 1 << endl;
Both of these loops correctly yield 3 in the case of:
set<int> foo{0, 1, 2, 4};
But the second loop incorrectly yields 3 instead of 4 in this case:
set<int> foo{0, 1, 2, 3};
How can I write this using an STL algorithm and accomplish the behavior of the first loop?
EDIT:
After seeing some of the answers, I'd like to increase the difficulty. What I really want is something that doesn't require temporary variables and can be placed in a cout
statement.
Have you tried
adjacent_find
?EDIT: OK, if you consider Boost standard enough, you can do this, which is damn nice:
Live example.
EDIT 2: another one I thought of while reading another question:
Which is just another way of previus one with
mismatch
.The problem with your loop is that you stop one element too early. This works:
The difference to the first loop is the condition
*prev(i) + 1 == *i)
instead of*i + 1 == *next(i)
; the range you check has to shift accordingly.You could also use
std::adjacent_find
:Response to the edit: A way to make it prettily inlineable is
...but this is less efficient because it does not short-circuit when it finds a gap. Another way that does short-circuit is
You're hitting a fringe case. Your while loop is failing once i == location at the end of the set. In this case it is ending at i == 3. You need to let i walk past the bounds of your array in order to make this work.
You can do this by changing line 2 to :
By making it <=, i will fail once it is past the value at the end of foo.
Here's a few other things to think about: 1) Sets aren't guaranteed to be sorted. 2) What happens in the situation where set foo(0, 1, 1); i.e. duplicates where the one that fails is correct but it is also the one at the end of the set?
You'll need a slightly more complex algorithm to catch all of these cases.