按顺序生成列表的所有分区的算法

时间:2014-08-23 05:48:52

标签: algorithm set partitioning

我需要一种特殊形式的'set'分区来逃避我,因为它不是完全分区的。或者更确切地说,它是维持原始顺序的特定列表的所有分区的子集。

我按特定顺序列出了 n 元素[a,b,c,...,n]

我需要获得维持顺序的所有离散变体分区。

因此,对于四个元素,结果将是:

[{a,b,c,d}]
[{a,b,c},{d}]
[{a,b},{c,d}]
[{a,b},{c},{d}]
[{a},{b,c,d}]
[{a},{b,c},{d}]
[{a},{b},{c,d}]
[{a},{b},{c},{d}]

我需要这个以在列表中生成所有可能的标记分组,这些标记必须保持其顺序,以便在更广泛的模式匹配算法中使用。

我发现只有一个与此特定问题有关的问题here,但它适用于红宝石。由于我不懂语言,看起来有人把代码放在一个搅拌器中,并且不仅仅是为了破译算法而学习语言,我觉得我没有选择。

我试图在很多方面以数学的方式解决这个问题,这让人很痛苦。我认为通过生成一个分区列表并以不同方式迭代它来越来越近,但每个元素的数量都需要不同的“模式”进行迭代,我不得不手动调整它们。

我无法知道可能有多少元素,而且我不想在我的处理上设置一个人工上限来限制它只是调整到我调整过的大小。

3 个答案:

答案 0 :(得分:4)

您可以将问题想象如下:您想要的每个分区都由0到2 ^(n-1)之间的整数表征。这种数字的二进制表示中的每个1对应于一个"分区中断"两个连续数字之间,例如

 a b|c|d e|f
  0 1 1 0 1

所以数字01101对应于分区{a,b},{c},{d,e},{f}。要从已知的分区号生成分区,请循环遍历列表,并在设置相应位时切断新子集。

我可以理解你阅读时尚功能编程风格的Ruby示例的痛苦。如果有帮助的话,这里是Python的完整示例。

array = ['a', 'b', 'c', 'd', 'e']
n = len(array)

for partition_index in range(2 ** (n-1)):

    # current partition, e.g., [['a', 'b'], ['c', 'd', 'e']]
    partition = []

    # used to accumulate the subsets, e.g., ['a', 'b']
    subset = []

    for position in range(n):

        subset.append(array[position])

        # check whether to "break off" a new subset
        if 1 << position & partition_index or position == n-1:
            partition.append(subset)
            subset = []

    print partition

答案 1 :(得分:1)

这是我在Python中递归实现分区问题。对我来说,递归解决方案总是更容易理解。您可以在here中找到有关它的更多说明。

# Prints partitions of a set : [1,2] -> [[1],[2]], [[1,2]] 
def part(lst, current=[], final=[]):
    if len(lst) == 0 :
        if len(current) == 0:
            print (final)
        elif len(current) > 1:
            print ([current] + final)
    else :
        part(lst[1:], current + [lst[0]], final[:])
        part(lst[1:], current[:], final + [[lst[0]]])

答案 2 :(得分:0)

由于没有人提到解决此问题的回溯技术。这是使用回溯解决此问题的Python解决方案。

def partition(num):
    def backtrack(index, chosen):
        if index == len(num):
            print(chosen)
        else:
            for i in range(index, len(num)):
                # Choose
                cur = num[index:i + 1]
                chosen.append(cur)

                # Explore
                backtrack(i + 1, chosen)

                # Unchoose
                chosen.pop()

    backtrack(0, [])


>>> partition('123')

['1', '2', '3']
['1', '23']
['12', '3']
['123']