无法理解Python的递归函数

时间:2018-03-11 02:34:17

标签: python function recursion

我一直在寻找这个问题的解决方案(下面)几个小时,并且无法弄清楚递归是如何工作的。有人可以用基本的术语解释它是如何工作的。

由于组被追加然后弹出,弹出列表是不是总是等于没有[]?

# Given a  list of ints, is it possible to choose a group of some of the   
# ints, such that the group sums to the given target?
#   0, 2, 4, 8, 10 -> True                                                  
#   0, 2, 4, 8, 14 -> True                                                  
#   0, 2, 4, 8, 9 -> False   

def sum_checker(ints, total, group, index):
    if sum(group) > total:            # backtracking
        return False
    if index == len(ints):            # BASE CASE
        return sum(group) == total

    group.append(ints[index])
    if sum_checker(ints, total, group, index + 1):
        return True
    group.pop()
    return sum_checker(ints, total, group, index + 1)


ints = [int(input()) for i in range(int(input()))]
total = int(input())
group = []
print(sum_checker(ints, total, group, 0))

3 个答案:

答案 0 :(得分:1)

确定。所以,让我们首先考虑这个没有真正代码的问题。试想这个策略:

  1. 我们逐个测试ints的每个元素,通过选择当前值和先前的选择进行检查,我们可以获得目标总和。
  2. 例如,ints= [1, 2, 4, 8]target = 11
  3. 我们尝试选择1,我们不知道在检查其他元素之前是否可以获得目标,因此我们会继续检查,并将1放在您手中。
  4. 现在我们遇见2,仍然不知道,只需选择并继续。
  5. 4相同。
  6. 哎呀,我们有sum=1+2+4+8 = 13 > 11。 [1,2,4,8]是一个糟糕的选择计划。如果我们有其他选择,让我们从最后退出并且谢谢。删除8
  7. 现在我们有sum=1+2+4=7,但我们无法添加更多元素,因为我们到达ints的末尾。删除4以查看是否有更多选择。
  8. 我们现在持有1+2,应该从8查看11!我们做到了!
  9. 因此,请使用铅笔和纸张自己尝试这个过程。这里的核心思想是维护一个我们已选择的数组,在您的代码中为group,然后检查是否可以基于此来达到目标选择+新元素。如果没有,请修改我们已选择的数组并继续。

答案 1 :(得分:1)

  

不是弹出列表总是等于没有[]?

并非总是如此。在第三个if语句中,它递归地添加到组列表中,并且仅当该调用堆栈返回时(当组的总和超过总数,或者索引超出输入范围时),最近推送的值是否会弹出。

在第一个输入的执行顺序中,这是组值

0   
0, 2   
0, 2, 4  
0, 2, 4, 8... Sum is greater than 10, return False   
8 is popped, and the previous index increases      
0, 2, 4.... The index is out of range, and the group sum is not the total
4 is popped and the previous index increases   
0, 2, 8... This is equal to 10, so we return True back up the call stack 

在展开递归结束时,是的,组列表将为空,但输出只需要一个布尔值,而不是跟踪符合条件的组

答案 2 :(得分:1)

关于您group被追加和弹出的问题。请记住声明

if sum_checker(ints, total, group, index + 1):

再次开始搜索(这次是下一个索引)。跟你的例子说。

sum_checker(
    ints=[0, 2, 4, 8],
    total=10,
    group=[],
    index=0
)

我们第一次点击群组时,会将0追加到group,因此我们会使用参数调用sum_checker

sum_checker(
    ints=[0, 2, 4, 8],
    total=10,
    group=[0],
    index=1
)

然后,由于group已有一个元素,我们会将2追加到group。所以我们有:

sum_checker(
    ints=[0, 2, 4, 8],
    total=10,
    group=[0, 2],
    index=2
)

这意味着,在我们到达group之前,我们开始填写.pop()。如果sum()的{​​{1}}变得过大,那么我们会执行第一个group,并在没有添加最后一个元素的情况下再次开始检查。