【问题标题】:DFS problem solving with recursion how does it work?使用递归解决 DFS 问题它是如何工作的?
【发布时间】:2020-09-10 22:06:14
【问题描述】:

问题来了

有 n 个非负整数。我们想适当地添加或减去这些数字以形成我们的目标数字。例如,要将数字 3 从 [1, 1, 1, 1, 1] 中取出,可以使用以下五种方法:

-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3

编写求解函数,在给定数组编号、目标编号和目标作为参数时,通过适当地加减数字来返回得到目标编号的方法数。

限制

  • 给出的数字数量为 2 或更多且 20 或更少。
  • 每个数字都是从 1 到 50 的自然数。
  • 目标数是从 1 到 1000 的自然数。

I/O 示例

numbers: [1,1,1,1,1]
target: 3
return: 5

接近

                                    1

                                  /   \

                               -1       1

                             /   \     /   \

                           -1     1  -1     1
                           
                           -1     1   1     3

以DFS方式找到这种方法,检查所有情况,加法或减法,如果数字组合等于目标数字然后计数。

代码如下:

def solution(numbers, target):
    total = 0
    num_len = len(numbers)

    def dfs(index=0):
        if index < num_len:
            numbers[index] *= 1
            print('positive / index', index, numbers)
            dfs(index + 1)

            numbers[index] *= -1
            print('negative / index', index, numbers)
            dfs(index + 1)

        else:
            if sum(numbers) == target:
                nonlocal total
                total += 1
                print('matched / index', index, numbers)

    dfs()

    return total

但是,我想知道它是如何运行的,控制台日志也是如此。

positive / index 0 [1, 1, 1, 1, 1]
positive / index 1 [1, 1, 1, 1, 1]
positive / index 2 [1, 1, 1, 1, 1]
positive / index 3 [1, 1, 1, 1, 1] 
positive / index 4 [1, 1, 1, 1, 1]
negative / index 4 [1, 1, 1, 1, -1]
matched / index 5 [1, 1, 1, 1, -1]
negative / index 3 [1, 1, 1, -1, -1] ### how come this index all of sudden becomes 3? ###
positive / index 4 [1, 1, 1, -1, -1]
                ...

我有点理解索引的增量递归直到匹配/索引 5 但不太清楚为什么下次它变成 3。

【问题讨论】:

    标签: python recursion depth-first-search


    【解决方案1】:

    日志记录格式可能会让您感到困惑。在 5 之后,将不再进行递归调用,因此下一个打印行与一个较旧的堆栈帧相关联,该堆栈帧一直在等待其子级解决,然后再探索下一个递归调用链。

    如果你添加缩进,你会更清楚地看到父子关系:

    print("  " * index + 'positive', numbers)
    
    0 1 2 3 4 5     stack depth
    ===========================
    positive [1, 1, 1, 1, 1]
      positive [1, 1, 1, 1, 1]
        positive [1, 1, 1, 1, 1]
          positive [1, 1, 1, 1, 1]
            positive [1, 1, 1, 1, 1]
            negative [1, 1, 1, 1, -1]
              matched [1, 1, 1, 1, -1]
          negative [1, 1, 1, -1, -1]  <-- here's the call you asked about
          ... calls continue ...
    

    在这里,您可以看到您的问题所涉及的否定分支回到深度 3,并且不是 matched 的子级。在matched 调用之后,没有更多子节点可供探索,堆栈弹回父级,父级也没有更多节点可供探索,并在深度 2 处弹回其父级,该父级仍有其negative 子级调用链进行探索,它确实如此,产生了对深度 3 的第二次调用。

    【讨论】:

    • 所以就像递归函数的工作方式一样,调用自己直到它可以向后运行,depth3 到达终点(没有更多可走)同时其他人等待所以查找 depth2 仍然有一些去我问的那个,当时它叫 index3?
    • 是的,没错。当一个函数被调用时,它不能完成执行,直到每个孩子递归解决。顶层函数处于“暂停”状态,直到它的所有子节点都计算出可以进行多少匹配,一直到停止产生调用的终端节点。如您的图像所示,创建了一个分支的调用树,尝试了所有合法的可能性。
    • 您还可以在每个函数的末尾添加一个打印,上面写着“已完成此堆栈帧”或其他内容,您会在从深度 5 返回深度 3 的路上看到这些弹出匹配。
    猜你喜欢
    • 2020-03-26
    • 2022-01-25
    • 2022-08-23
    • 2020-06-30
    • 2019-08-16
    • 1970-01-01
    • 2021-01-11
    • 2022-01-10
    • 2021-04-14
    相关资源
    最近更新 更多