创建特定大小的可能组合

时间:2016-02-12 11:23:18

标签: python algorithm

字符串/列表是例如'foobar的'。我需要在所有可能的组合中将其分解,其中组的数量是n,例如3。

这会给我带来例如。

['foo', 'ba',  'r']
['f',  'ooba', 'r']
['fo', 'oo',   'bar']
['f',  'o',    'obar']

创建所有可能组合的最佳算法是什么?

5 个答案:

答案 0 :(得分:5)

听起来像是itertools的工作:

from itertools import combinations

def compositions(s,k):
    n = len(s)
    for c in combinations(range(1,n),k-1):
        yield [s[i:j] for i,j in zip((0,)+c,c+(n,))]

它的工作方式是combinations部分产生由可能的切割点组成的元组。例如(使用s = "foobar"k = 3(2,4)是其中一个元组。打破这些索引应该产生["fo","ob","ar"],其对应于[s[0:2],s[2,4],s[4,6]],在这种情况下,表达式zip((0,)+c,c+(n,))zip((0,2,4),(2,4,6))相同,因此迭代它具有迭代过程的效果连续切片的连续索引对。

例如,

>>> for c in compositions("foobar",3): print(c)

['f', 'o', 'obar']
['f', 'oo', 'bar']
['f', 'oob', 'ar']
['f', 'ooba', 'r']
['fo', 'o', 'bar']
['fo', 'ob', 'ar']
['fo', 'oba', 'r']
['foo', 'b', 'ar']
['foo', 'ba', 'r']
['foob', 'a', 'r']

我选择了名字"作曲"因为你基本上是在谈论组合学中的compositions。我的算法基于链接文章中的证明,n个项目的成分数为k个C(n-1,k-1)

答案 1 :(得分:2)

这是一个简单的递归

CREATE PROCEDURE [dbo].[usp_test]
(
    @result int OUT
)
AS
BEGIN

--DO STUFF

SET @result = 0
Select @result
END

def split(s, n): def rec_split(i, s, n): ans = [] if n == 1: ans.append([s[i:]]) return ans for j in range(i+1, len(s)): head = s[i:j] tails = rec_split(j, s, n-1) for tail in tails: ans.append([head] + tail) return ans return rec_split(0, s, n) for e in split("foobar", 3): print(e) # ['f', 'o', 'obar'] # ['f', 'oo', 'bar'] # ['f', 'oob', 'ar'] # ['f', 'ooba', 'r'] # ['fo', 'o', 'bar'] # ['fo', 'ob', 'ar'] # ['fo', 'oba', 'r'] # ['foo', 'b', 'ar'] # ['foo', 'ba', 'r'] # ['foob', 'a', 'r'] 返回rec_splits部分中n部分的所有分区

答案 2 :(得分:0)

看一下Word break算法,这是它的一个变体,它有一个显着的区别,即单词不是来自预定义的字典,而是需要在最终集合中有固定数量的单词

主要思想是从头开始迭代输入,切片并递归处理正确的部分。

假设具有原型的功能

def rec(input, n):

这是伪代码:

if n == 1:
    final_set.append([input[i:]])
else:
    for i in range (0, len(input) - n + 1):
       for rec_set in rec(input[i:], n - 1):
           final_set.append(merge(input[:i], rec_set))

使用您的示例,我们有:

rec('foobar', 3)
= {['f', rec('oobar', 2)], ['fo', rec('obar', 2)], ['foo', rec('bar', 2)], ['foob', rec('ar', 2)]}

= {['f','o', rec('obar', 1)], ['f','oo', rec('bar', 1)], ['f','oob', rec('ar', 1)], ['f','ooba', rec('r', 1)], ['fo', 'o', rec('bar', 1)], ['fo', 'ob', rec('ar', 1)], ['fo', 'oba', rec('r', 1)], ['foo', 'b', rec('ar', 1)], ['foo', 'ba', rec('r', 1)], ['foob', 'a', rec('r', 1)]}

= {['f','o', 'obar'], ['f','oo', 'bar'], ['f','oob', 'ar'], ['f','ooba', 'r'], ['fo', 'o', 'bar'], ['fo', 'ob', 'ar'], ['fo', 'oba', 'r',], ['foo', 'b', 'ar'], ['foo', 'ba', 'r'], ['foob', 'a', 'r']}

要记住的重要一点是缓存部分结果,以避免重复执行相同的工作。例如,如果您已经计算rec('oobar', 2)将结果存储在某个缓存中(例如,字典适合于此),并在函数的开头检查您是否已经为指定的输入字符串和{{计算了所有可能的组合1}}。它将时间复杂度从指数降低到多项式。

答案 3 :(得分:0)

您可以使用backtracking。每当你将单词分成三个以上的部分时,就会产生所有可能的分裂和回溯。

答案 4 :(得分:0)

您可以使用生成器递归解决此问题:

def sections(s, n):
    if n == 1:
        yield [s]

    if n > 1:
        for i in range(1, len(s)):
            for tail in section(s[i:], n - 1):
                yield [s[0:i]] + tail

并像这样使用它:

for s in sections("foobar", 3):
    print s