打印n使用递归选择k组合算法

时间:2017-07-04 21:32:21

标签: python algorithm recursion combinations

这必须是一个经典的面试问题,然而,我在理解它时遇到了问题。

下面是我在Python中的实现,如果你运行它,它只打印ab, ac, ad。它没有进入'b' (bc, bd)级别。

def Print_nCk (the_list, k, str_builder, used):
    if len(str_builder) == k:
        print str_builder
        return 
    else:
        for i in xrange(len(the_list)):
            if used[i] !=True:
                str_builder+=the_list[i]
                used[i] = True
                Print_nCk(the_list, k, str_builder, used)
                str_builder = str_builder[:-1]


Print_nCk(['a','b','c','d'], 2, "",[False,False,False,False])

当上面的行传递时,正确的答案是ab,ac,ad,bc,bd,cd

我从这里知道正确的实现而不使用used param(http://www.geeksforgeeks.org/print-all-possible-combinations-of-r-elements-in-a-given-array-of-size-n/)但是 我的问题是我的实施有什么问题?

你能说清楚吗?

要进行调试,我打印出来"使用"每次。打印后,used参数变为(真,真,真,真)" ad"那么它并没有比这更深入。如果我坚持使用used,那么解决used的明智方法是什么?

2 个答案:

答案 0 :(得分:3)

当您回溯时,您忘记取消设置used[i]

def Print_nCk (the_list, k, str_builder, used):
    if len(str_builder) == k:
        print str_builder
        return
    else:
        for i in xrange(len(the_list)):
            if used[i] != True:
                str_builder += the_list[i]
                used[i] = True
                Print_nCk(the_list, k, str_builder, used)
                str_builder = str_builder[:-1]
                used[i] = False


Print_nCk(['a','b','c','d'], 2, "",[False,False,False,False])

在您当前的实施中,您从选择 used[i]作为值时,将True设置为i。如果稍后您决定选择另一个分支,则应正确进行簿记,从而取消设置used[i]

请注意,现在会生成"ab""ba"。因此,生成具有对称性的组合。如果您不想这样,可以使用附加参数。这样可以确保您使用的索引不低于之前选择的索引

def Print_nCk (the_list, k, str_builder, used, prev = 0):
    if len(str_builder) == k:
        print str_builder
        return
    else:
        for i in xrange(prev,len(the_list)):
            if used[i] != True:
                str_builder += the_list[i]
                used[i] = True
                Print_nCk(the_list, k, str_builder, used, i+1)
                str_builder = str_builder[:-1]
                used[i] = False


Print_nCk(['a','b','c','d'], 2, "",[False,False,False,False])

然而,这或多或少地违背了使用“使用过的”阵列的目的。您只需使用prev

即可
def Print_nCk (the_list, k, str_builder, prev = 0):
    if len(str_builder) == k:
        print str_builder
        return
    else:
        for i in xrange(prev,len(the_list)):
            str_builder += the_list[i]
            Print_nCk(the_list, k, str_builder, i+1)
            str_builder = str_builder[:-1]


Print_nCk(['a','b','c','d'], 2, "")

然后打印:

>>> Print_nCk(['a','b','c','d'], 2, "")
ab
ac
ad
bc
bd
cd

答案 1 :(得分:2)

派对迟到了,但我认为你应该更多地利用递归。没有必要传递任何多余的论据。

这是一种更简单的方法:

def Print_nCk(the_list, size):
    combs = []
    if size == 1: # the base case
        return the_list

    for i, c in enumerate(the_list[:-size + 1]):
        for sub_comb in Print_nCk(the_list[i + 1:], size  - 1): # generate and return all sub-combos of size - 1
            combs.append(c + sub_comb) # for each sub-combo, add the sizeth (or n - sizeth) character

    return combs

此方法生成size - 1的组合,并将它们与size字符组合。

对于size-2组合:

>>> Print_nCk(['a','b','c','d'], 2)
['ab', 'ac', 'ad', 'bc', 'bd', 'cd']

对于3号组合:

>>> Print_nCk(['a','b','c','d'], 3)
['abc', 'abd', 'acd', 'bcd']