简体   繁体   English

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

[英]Print n choose k combination algorithm using recursion

This must be a classic interview question, however, I'm having a problem understanding it. 这一定是一个经典的面试问题,但是,我在理解它时遇到了问题。

Below is my implementation in Python and if you run it, it's only printing ab, ac, ad . 下面是我在Python中的实现,如果您运行它,它只会打印ab, ac, ad It doesn't go to the 'b' (bc, bd) level. 它不会达到'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])

The right answer is ab,ac,ad,bc,bd,cd when above line is passed. 当以上行通过时,正确的答案是ab,ac,ad,bc,bd,cd

I know the right implementation from here without using used param ( http://www.geeksforgeeks.org/print-all-possible-combinations-of-r-elements-in-a-given-array-of-size-n/ ) but my question is what is wrong is my implementation? 我从这里知道正确的实施方式,而不使用used参数( http://www.geeksforgeeks.org/print-all-possible-combinations-of-r-elements-in-a-given-array-of-size-n/ ),但我的问题是我的实现有什么问题?

Can you shed some light on it? 你能阐明一点吗?

To debug, I printed out "used" every time. 为了调试,我每次都打印出“二手”。 The used param becomes (True, True, True, True) after printing "ad" then it doesn't go deeper than that. 打印“ ad”后,已used参数变为(True,True,True,True),然后没有比这更深的了。 What's the smart way to fix the used , if I insist on using used ? 如果我坚持使用used货,修复used货的明智方法是什么?

You forgot to unset used[i] when you backtrack : 回溯时,您忘记取消设置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])

In your current implementation, you set used[i] to True from the moment you pick the i as value. 在当前的实现中,从选择 i作为值的那一刻起,您就将used[i]设置为True If however later, you decide to pick another branch, you should do the bookkeeping correctly and thus unset the used[i] . 但是,如果稍后您决定选择另一个分支,则应正确进行簿记,从而取消设置used[i]

Note that now "ab" and "ba" will be generated. 请注意,现在将生成"ab""ba" You thus generate combinations with symmetry . 因此,您将生成具有对称性的组合 If you do not want that, you can use an additional parameter . 如果不希望这样,可以使用附加参数 That makes sure that you do not use an index lower than the previously picked one : 这样可以确保您使用的索引不低于先前选择的索引

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

Nevertheless, this more or less defeats the purpose of using a "used" array. 然而,这或多或少地破坏了使用“二手”阵列的目的。 You can simply use the prev : 您可以简单地使用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, "")

This then prints: 然后打印:

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

Bit late to the party, but I think you should take more advantage of recursion. 参加聚会有点晚,但是我认为您应该更多地利用递归。 There's no need to pass any superfluous arguments. 无需传递任何多余的参数。

Here's a simpler approach: 这是一个更简单的方法:

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

This approach generates combinations of size - 1 and combines them with the size th character. 此方法生成size - 1组合,并将它们与size th的字符组合在一起。

For size-2 combinations: 对于2号组合:

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

For size-3 combinations: 对于3号组合:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM