【问题标题】:Python itertools permutations without repetitionsPython itertools 无重复排列
【发布时间】:2020-02-16 18:54:02
【问题描述】:

我有一个字符串显示 m x n 网格中的步骤,如下所示: https://leetcode.com/problems/unique-paths/

step = 'DDRR'

D 表示向下,R 表示向右 我想显示没有替换的排列,我发现了 Python 内置的 itertools。但是它说:

元素根据它们的位置而不是它们的值被视为唯一的。所以如果输入元素是唯一的,就不会有重复值。

所以当我使用 itertools.permutation(step,4) 时,它包含许多复制。

>>> 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')

我想要类似的东西:

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

我使用 set(itertools.permutations(step,4)) 找到了一些答案,但由于应用 set() 方法,itertools.permutation() 方法仍然计算所有可能性。有没有办法避免它,或者是否有任何内置函数可以在 Python 中进行不重复的排列

【问题讨论】:

  • 我使用itertools.permutations(step,4) 得到空列表,也许你的意思是step = list('DDRR')
  • 我的怀疑是,任何计算没有重复的排列的算法都不会比你在问题中提到的 itertools 和 set 方法更有效(可能效率更低),所以可能不值得担心,除非你将使用更长的字符串。
  • @SimonN “多长时间”?对于DDDDDRRRRR,已经有 360 万个排列,但只有 252 个不同的排列,因此仅产生后者的合理方法应该不会有更快的问题。
  • 所以你想计算精确排列 (m-1) D 符号和 (n-1) R 的不同组合的数量,或者等效地 n R 符号和 (m -1)它们之间的酒吧|。 (您不需要计算实际的组合,并且对于 m,n 最多 100 这将是令人望而却步的)。方式数由众所周知的Stars-and-Bars formula给出
  • @SimonN:这完全不正确,请记住 C(n,k) 的数量级为 O(2^n),因此对于非玩具值,您将很快耗尽内存和 CPU n. [记住[sum(C(n,k)) over k] = 2^n]的恒等式

标签: python permutation itertools combinatorics


【解决方案1】:

要获得您需要的答案,您可以使用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']]

要获得总数,请使用项数的阶乘除以阶乘的乘积来计算每个唯一项的计数。这里有2个D和2个R

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

【讨论】:

    【解决方案2】:

    无论如何,这是一个非常低效的解决方案。直接计算数字即可:

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

    【讨论】:

    • 请注意,math.comb 仅在 Python 3.8+ 中可用。
    • @blhsing 是的,LeetCode 运行 3.8.1。
    【解决方案3】:

    leetcode问题只问唯一路径的个数,而不是唯一路径的列表,所以计算个数只需要用C(n, k) = n! / (k! x (n - k)!)的组合公式求Ds所在的位置个数(或Rs)可以放在所有位置之外:

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

    这样f(3, 2) 返回:3

    f(7, 3) 返回:28

    另一方面,如果您对生成唯一路径列表感兴趣,可以使用itertools.combinations 执行与上述相同的操作;即在所有位置中找出Ds(或Rs)可以放置的位置:

    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))
    

    这样:

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

    输出:

    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
    

    【讨论】:

      【解决方案4】:

      尝试使用 itertools.combinationss(step,4) 代替 itertools.permutations(step,4)

      【讨论】:

      • itertools.combinationss(step,4) 将只返回 ('D', 'D', 'R', 'R')
      • 那就用这个吧,itertools.combinations_with_replacement(step,4)
      • 我也尝试了组合、combinations_with_replacement、permutations 和 product,但我无法得到我想要的
      • 没有。 itertools.permutations 枚举了所有排列(有大量重复项),但这太过分了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-10
      • 2018-11-12
      • 1970-01-01
      • 1970-01-01
      • 2021-06-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多