Reputation: 2028
How can I generate permutations given the following conditions?
So let's say for N = 3 and K = 5, so the correct result should be:
{1, 1, 1, 4, 4} , {1, 1, 4, 1, 4} , {4, 4, 4, 1, 1} , etc..
The following are example of invalid or incorrect results:
{1, 1, 1, 1, 4} -> 1 appear 4 times (1 should appear not greater than 3 times)
{1, 4, 4, 4, 1, 1} -> the size of the list is 6 (the size should be exactly 5)
Also, each permutation should be unique, meaning no duplicates.
I hope I can get the best solution or algorithm for this problem.
Thanks in advance. :)
Upvotes: 3
Views: 1215
Reputation: 25197
Starting from here (as in Abhijit's answer)...
>>> K=5
>>> N=3
>>> [['1']*n+['4']*(K-n) for n in xrange(K-N,N+1)]
[['1', '1', '4', '4', '4'], ['1', '1', '1', '4', '4']]
...you could then Generate permutations of list with repeated elements for each list. Also, handle the case if N < K-N, perhaps by setting N=max(N,K-N)
Upvotes: 2
Reputation: 63727
See if this works for you
>>> K=5
>>> N=3
>>> src=[['1']*n+['4']*(K-n) for n in xrange(K-N,N+1)]
>>> set(x for s in src for x in itertools.permutations(s))
set([('1', '4', '1', '4', '1'), ('4', '1', '4', '1', '1'), ('1', '1', '4', '4', '4'), ('1', '4', '4', '1', '1'), ('1', '4', '4', '4', '1'), ('4', '4', '4', '1', '1'), ('4', '1', '1', '4', '1'), ('4', '4', '1', '4', '1'), ('1', '4', '1', '1', '4'), ('4', '1', '4', '4', '1'), ('1', '1', '4', '4', '1'), ('1', '4', '4', '1', '4'), ('4', '1', '4', '1', '4'), ('4', '1', '1', '1', '4'), ('4', '4', '1', '1', '4'), ('1', '4', '1', '4', '4'), ('1', '1', '4', '1', '4'), ('4', '4', '1', '1', '1'), ('4', '1', '1', '4', '4'), ('1', '1', '1', '4', '4')])
Note**
First create all possible combination possible with '1' and '4'. Please note with the restriction of maximum N instances of particular integer, so in a set of K numbers if there are i instances of x then there is (K-i) instances of y for two numbers (x,y). In that case both i and x should be in the range [K-N,N].
Now the next step is to use a generator comprehension to create all possible iteration of all possible instances of the above set. I am using a set comprehension to remove any duplicate and also using generator to not store the intermediate duplicate results.
Upvotes: 4
Reputation: 19601
For small values of K I would count from 0 to 2^K - 1, skipping values where the binary representation has more than N 0s or more than N 1s, and then translate 0 bits to '1' and 1 bits to '4'.
For large values of K you could use backtracking search -
PseudoCode (int N, int K, int num1s, int num4s, String sofar)
if (num1s > K)
return
if (num4s > K)
return
length(sofar) == N
print sofar
return
PseudoCode (N, K, num1s + 1, num4s, sofar + "1")
PseudoCode (N, K, num1s, num4s + 1, sofar + "4")
Upvotes: 0
Reputation: 56915
This is one way to think about it, although I wonder at a more elegant solution:
Suppose N = 3 and K = 5 like above.
Instead of your '1' and '4' I'm going to use a
and b
or else I'll confuse myself :P
Since each symbol (a
or b
) is only allowed to appear 3 times at most, it means we want to get all permutations of:
a
s in a string of 5 b
sa
s in a string of 5 b
sSo we only need to find all permutations of {a,a,b,b,b}
and {a,a,a,b,b}
.
Generalising this, you only need to find permutations of {m lots of a, and (K-m) lots of b}
, where m
is in { K-N, K-N+1, K-N+2, ... N }
.
One way to do this is:
m = K-N
.b
of length K, call it x
.x
(i.e. 0,1,2,..,K-1
), and find all subsets of length m
into this. These will be where we place the a
s.m = K-N, K-N+1, ... , N
.To do step 4, we use the module itertools
, and in particular, itertools.combinations
.
So:
import itertools
def notQuitePermutations(N,K,symbol1,symbol2):
permutations = []
base_perm = [symbol2]*K # step 3
for m in range(K-N,N+1): # +1 so we *include* N
# step 4: find m places to put symbol1 in.
idxs = itertools.combinations(range(K),m)
for idx in idxs:
perm = base_perm[:] # make a copy of base_perm
for i in idx:
perm[i] = symbol1 # put symbol1 in.
# add this permutation to the list
permutations += [perm]
return permutations
Then:
>>> notQuitePermutations(3,5,1,4)
[[1, 1, 4, 4, 4], [1, 4, 1, 4, 4], [1, 4, 4, 1, 4],....
Another alternative is to find all permutations of {m lots of symbol1, and (K-m) lots of symbol2}
, using itertools.permutations
. Except that you get duplicates there (since Python does permutations based off unique positions of elements, not unique values of elements). Then you need to filter them out afterwards, which could get expensive once K
and N
get large. That's why I chose the above approach, because it doesn't have the problem of duplicates.
Upvotes: 1