给定特定条件的排列的Python实现

时间:2011-12-16 05:21:00

标签: python algorithm permutation

如果满足以下条件,我如何生成排列?

  1. 有两个整数,例如。 1和4。
  2. 给出的两个整数将是排列的一部分,其中每个整数最多出现 N 次,每个排列的大小为 K
  3. 让我们说 N = 3 K = 5 ,所以正确的结果应该是:

      

    {1,1,1,4,4},{1,1,4,1,4},{4,4,4,1,1}等。

    以下是无效或不正确结果的示例:

      

    {1,1,1,1,4} - > 1出现4次(1次出现不应超过3次)

         

    {1,4,4,4,1,1} - >列表的大小是6(大小应该是5)

    此外,每个排列应该是唯一的,这意味着没有重复。

    我希望我能为这个问题找到最佳解决方案或算法。

    提前致谢。 :)

4 个答案:

答案 0 :(得分:4)

看看这是否适合你

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

注* *

首先使用'1'和'4'创建所有可能的组合。请注意特定整数的最大N个实例的限制,因此在一组K个数中,如果有i个实例,那么对于两个数字(x,y)存在y的(K-i)个实例。在这种情况下,i和x都应该在[K-N,N]范围内。

现在,下一步是使用生成器理解来创建上述集合的所有可能实例的所有可能迭代。我使用set comprehension删除任何重复项,并使用生成器不存储中间重复结果。

答案 1 :(得分:2)

从这里开始(如Abhijit的回答)......

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

...然后您可以为每个列表Generate permutations of list with repeated elements。此外,如果N <1,则处理该情况。 K-N,可能是设置N=max(N,K-N)

答案 2 :(得分:1)

这是考虑它的一种方式,虽然我想知道更优雅的解决方案:

假设N = 3且K = 5,如上所述。 而不是你的'1'和'4'我会使用ab,否则我会迷惑自己:P

由于每个符号(ab)最多只能出现3次,这意味着我们希望获得以下所有排列:

  • 2 a s,串成5 b s
  • 3 a s,串成5 b s

因此,我们只需找到{a,a,b,b,b}{a,a,a,b,b}的所有排列。

对此进行概括,您只需找到{m lots of a, and (K-m) lots of b}的排列,其中m位于{ K-N, K-N+1, K-N+2, ... N }

一种方法是:

  1. 设置N,K。
  2. 设置m = K-N
  3. 制作一个填充{K}长度为b的列表,并将其命名为x
  4. 将索引列入 x(即0,1,2,..,K-1),并找到长度为m的所有子集。这些将是我们放置a s。
  5. 的位置
  6. 重复m = K-N, K-N+1, ... , N
  7. 要执行第4步,我们使用模块itertools,尤其是itertools.combinations

    所以:

    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
    

    然后:

    >>> notQuitePermutations(3,5,1,4)
    [[1, 1, 4, 4, 4], [1, 4, 1, 4, 4], [1, 4, 4, 1, 4],....    
    

    另一种方法是使用{m lots of symbol1, and (K-m) lots of symbol2}查找itertools.permutations的所有排列。除了你在那里得到重复之外(因为Python根据元素的唯一位置进行排列,而不是元素的唯一值)。然后,您需要在之后对其进行过滤,一旦KN变大,这可能会变得昂贵。这就是我选择上述方法的原因,因为它没有重复的问题。

答案 3 :(得分:0)

对于小的KI值将从0到2 ^ K-1计数,跳过二进制表示具有大于N 0或大于N 1的值,然后将0位转换为'1'并将1位转换为' 4' 。

对于较大的K值,您可以使用回溯搜索 -

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