【问题标题】:Python implementation for permutation given specific conditions给定特定条件的排列的 Python 实现
【发布时间】:2012-01-21 17:47:41
【问题描述】:

如何在给定以下条件的情况下生成排列?

  1. 有两个整数,例如。 1 和 4。
  2. 给定的两个整数将是排列的一部分,其中每个整数最多出现 N 次,每个排列的大小为 K

假设 N = 3K = 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)

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

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

提前致谢。 :)

【问题讨论】:

    标签: python algorithm permutation


    【解决方案1】:

    从这里开始(如 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 N=max(N,K-N)

    【讨论】:

      【解决方案2】:

      看看这是否适合你

      >>> 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 的实例,那么对于两个数字 (x,y) 有 (K-i) 个 y 的实例。在这种情况下,i 和 x 都应该在 [K-N,N] 范围内。

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

      【讨论】:

      • 嗨,我已经尝试过了,但我收到一条错误消息,提示“s”未定义。同样根据您的输出,4 总是最多只出现 2 次,还应该考虑像这样的排列 -> (4, 4, 4, 1, 1)。所以基本上你的输出不完整..谢谢你的努力..
      • @Manie,我解决了一个小问题。您现在应该得到类似于您提到的排列。顺便说一句,您使用的是什么版本的python?你能提供完整的堆栈跟踪吗?我看不出这不起作用的原因。试试看,如果失败,请提供堆栈跟踪。
      • 嗨,我明白了,我所做的是将集合(x for x in itertools.permutations(s) for s in src)重新排列为 set(x for s in src for x在 itertools.permutations(s)) 中,以获得正确的结果。
      • 是的,那是我的问题。您可以检查上面的修复程序。在理解 src 时也存在问题,现在已修复。
      • @Manie,顺便说一句,如果此解决方案有效,您可能希望选择此答案作为已接受的答案
      【解决方案3】:

      对于较小的 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")
      

      【讨论】:

        【解决方案4】:

        这是一种思考方式,尽管我想知道一个更优雅的解决方案:

        假设 N = 3 和 K = 5,如上。 我将使用 ab 而不是你的“1”和“4”,否则我会混淆自己:P

        由于每个符号(ab)最多只允许出现 3 次,这意味着我们要获取以下所有排列:

        • 2 as 在 5 个 bs 的字符串中
        • 3 as 在 5 个 bs 的字符串中

        所以我们只需要找到{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的所有子集。这些将是我们放置as 的地方。
        5. 重复m = K-N, K-N+1, ... , N

        要执行第 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],....    
        

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

        【讨论】:

        • 呃,忽略这个答案,@Abhijit's 好多了:P。我不知道set
        • 感谢您的精彩解释。无论如何,使用您的代码我尝试了类似这样的 len(notQuitePermutations(50,100,1,5)),我得到一个“MemoryError”,所以我猜它对于较大的值效率不高。我想要的是一种高效的算法。
        • 不,不要忽略这一点,对于较大的 N 和 K,它的效率要高得多。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多