I am trying to create a generator (iterator which supports doing a next, perhaps using yield in python) which gives all combinations of r elements from {1,2,...n} (n and r are parameters) such that in the selected r elements, no two are consecutive.
For example, for r = 2 and n= 4
The generated combinations are {1,3}, {1,4}, {2, 4}
.
I could generate all combinations(as an iterator) and filter those which don't satisfy the criteria, but we will be doing unnecessary work.
Is there some generation algorithm such that the next
is O(1) (and if that is not possible, O(r) or O(n)).
The order in which the sets are returned is not relevant (and hopefully will allow an O(1) algorithm).
Note: I have tagged it python, but a language-agnostic algorithm will help too.
Update:
I have found a way to map it to generating pure combinations! A web search reveals that O(1) is possible for combinations (though it seems complicated).
Here is the mapping.
Suppose we have a combination x_1, x_2, ... , x_r
with x_1 + 1 < x_2, x_2 + 1 < x_3, ...
We map to y_1, y_2, ..., y_r
as follows
y_1 = x_1
y_2 = x_2 - 1
y_3 = x_3 - 2
...
y_r = x_r - (r-1)
This way we have that y_1 < y_2 < y_3 ...
without the non-consecutive constraint!
This basically amounts to choosing r elements out of n-r+1. Thus all I need to do is run the generation for (n-r+1 choose r).
For our purposes, using the mapping after things are generated is good enough.
Reasons for choosing svkcr's answer
All great answers, but I have chosen svkcr's answer.
Here are some reasons why
It is effectively stateless (or "Markovian" to be more precise). The next permutation can be generated from the previous one. It is in a way almost optimal: O(r) space and time.
It is predictable. We know exactly the order(lexicographic) in which the combinations are generated.
These two properties make it easy to parallelise the generation (split at predictable points and delegate), with fault tolerance thrown in (can pick off from the last generated combination if a CPU/machine fails)!
Sorry, parallelisation was not mentioned earlier, because it didn't occur to me when I wrote the question and I got that idea only later.
itertools
. – abarnert