简体   繁体   中英

Python itertools permutations without repetitions

I have a string show the step going in mxn grid like this problem: https://leetcode.com/problems/unique-paths/

step = 'DDRR'

D mean go Down and R mean go to Right I want to show permutations without replacement, and i found the itertools built-in on Python.But it's say:

Elements are treated as unique based on their position, not on their value. So if the input elements are unique, there will be no repeat values.

So that when I using itertools.permutation(step,4), it's contain many replications.

>>> itertools.permutations(step,4)
('D', 'D', 'R', 'R')
('D', 'R', 'D', 'R')
('D', 'R', 'R', 'D')
('D', 'R', 'D', 'R')
('D', 'R', 'R', 'D')
('D', 'D', 'R', 'R')
('D', 'D', 'R', 'R')
('D', 'R', 'D', 'R')
('D', 'R', 'R', 'D')
('D', 'R', 'D', 'R')
('D', 'R', 'R', 'D')
('R', 'D', 'D', 'R')
('R', 'D', 'R', 'D')
('R', 'D', 'D', 'R')
('R', 'D', 'R', 'D')
('R', 'R', 'D', 'D')
('R', 'R', 'D', 'D')
('R', 'D', 'D', 'R')
('R', 'D', 'R', 'D')
('R', 'D', 'D', 'R')
('R', 'D', 'R', 'D')
('R', 'R', 'D', 'D')
('R', 'R', 'D', 'D')

I want something like:

('R', 'D', 'R', 'D')
('R', 'D', 'D', 'R')
('D', 'R', 'R', 'D')
('D', 'D', 'R', 'R')
('D', 'R', 'D', 'R')
('R', 'R', 'D', 'D')

I found some answer using set(itertools.permutations(step,4)) , but because apply set() method, the itertools.permutation() method still calculate all possibilities. Is there anyway to avoid it, or is there any built-in function can do permutation without repetitions in Python ?

To get the answer you need, you could use multiset_permutations

>>> from sympy.utilities.iterables import multiset_permutations
>>> from pprint import pprint
>>> pprint(list(multiset_permutations(['D','D','R','R'])))
[['D', 'D', 'R', 'R'],
 ['D', 'R', 'D', 'R'],
 ['D', 'R', 'R', 'D'],
 ['R', 'D', 'D', 'R'],
 ['R', 'D', 'R', 'D'],
 ['R', 'R', 'D', 'D']]

To get just the total number, use factorial of number of items divided by the product of factorials for the count of each unique item. Here there are 2 D's and 2 R's

>>> from math import factorial
>>> factorial(4)//(factorial(2)*factorial(2))
6

The leetcode problem only asks about the number of unique paths, not a list of unique paths, so to calculate the number you only need to use the combination formula of C(n, k) = n! / (k! x (n - k)!) C(n, k) = n! / (k! x (n - k)!) to find the number of positions where D s (or R s) can be placed out of all positions:

from math import factorial

def f(m, n):
    return factorial(m + n - 2) / factorial(m - 1) / factorial(n - 1)

so that f(3, 2) returns: 3

and that f(7, 3) returns: 28

On the other hand, if you're interested in producing a list of unique paths, you can use itertools.combinations to do the same as above; that is, to find the positions where D s (or R s) can be placed out of all positions:

from itertools import combinations
def f(m, n):
    for positions in map(set, combinations(range(m + n - 2), m - 1)):
        yield ''.join('DR'[i in positions] for i in range(m + n - 2))

so that:

print(*f(7, 3), sep='\n')

outputs:

RRRRRRDD
RRRRRDRD
RRRRRDDR
RRRRDRRD
RRRRDRDR
RRRRDDRR
RRRDRRRD
RRRDRRDR
RRRDRDRR
RRRDDRRR
RRDRRRRD
RRDRRRDR
RRDRRDRR
RRDRDRRR
RRDDRRRR
RDRRRRRD
RDRRRRDR
RDRRRDRR
RDRRDRRR
RDRDRRRR
RDDRRRRR
DRRRRRRD
DRRRRRDR
DRRRRDRR
DRRRDRRR
DRRDRRRR
DRDRRRRR
DDRRRRRR

It's a terribly inefficient solution anyway. Just compute the number directly:

math.comb(m + n - 2, m - 1)

尝试使用 itertools.combinationss(step,4) 而不是 itertools.permutations(step,4)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM