【问题标题】:Given a binary tree and a number ‘S’, find all paths from root-to-leaf such that the sum of all the node values of each path equals ‘S’给定一棵二叉树和一个数字“S”,找到从根到叶的所有路径,使得每条路径的所有节点值之和等于“S”
【发布时间】:2021-09-29 04:34:35
【问题描述】:

下面的示例来自在线来源,我不确定为什么我们需要在allPaths 上附加currentPath 的新副本。我认为在删除最后一个元素时,我们通过执行del currentPath[-1] 回到递归调用堆栈,确保我们没有将先前的路径添加到新路径中

class TreeNode:
  def __init__(self, val, left=None, right=None):
    self.val = val
    self.left = left
    self.right = right


def find_paths(root, required_sum):
  allPaths = []
  find_paths_recursive(root, required_sum, [], allPaths)
  return allPaths


def find_paths_recursive(currentNode, required_sum, currentPath, allPaths):
  if currentNode is None:
    return

  # add the current node to the path
  currentPath.append(currentNode.val)

  # if the current node is a leaf and its value is equal to required_sum, save the current path
  if currentNode.val == required_sum and currentNode.left is None and currentNode.right is None:
    allPaths.append(list(currentPath))
  else:
    # traverse the left sub-tree
    find_paths_recursive(currentNode.left, required_sum -
                         currentNode.val, currentPath, allPaths)
    # traverse the right sub-tree
    find_paths_recursive(currentNode.right, required_sum -
                         currentNode.val, currentPath, allPaths)

  # remove the current node from the path to backtrack,
  # we need to remove the current node while we are going up the recursive call stack.
  del currentPath[-1]


def main():

  root = TreeNode(12)
  root.left = TreeNode(7)
  root.right = TreeNode(1)
  root.left.left = TreeNode(4)
  root.right.left = TreeNode(10)
  root.right.right = TreeNode(5)
  required_sum = 23
  print("Tree paths with required_sum " + str(required_sum) +
        ": " + str(find_paths(root, required_sum)))


main()

【问题讨论】:

    标签: python list recursion depth-first-search


    【解决方案1】:

    重要的是要意识到在整个过程中只有一个 currentPath 列表。它是在初始调用中创建的:

    find_paths_recursive(root, required_sum, [], allPaths)
    #                                        ^^---here!
    

    该单个列表发生的所有事情都是元素被附加到它,然后再次从中删除(回溯时)。它在其整个生命周期中不断地增长和收缩,增长和收缩。但它是相同的单个列表实例。

    如果您将该列表附加到 allPaths 而不复制,即:

    allPaths.append(currentPath)
    

    ...然后意识到虽然该列表是allPaths 的成员,但它被未来的appenddelete 操作改变!甚至更多:因为上面的语句稍后会再次执行:

    allPaths.append(currentPath)
    

    ... 与allPaths... 中的完全相同相同 列表被追加,因为只有一个currentPath 列表!所以你最终会得到allPaths 重复引用同一个列表。

    结论:获取currentPath 的副本很重要,它不会再被currentPath 上的未来突变所改变。这就像拍摄currentPath当前状态的快照。

    【讨论】:

      【解决方案2】:

      find_paths_recursive 函数的设计使得附加到allPaths 是将结果返回给调用者的方式。

      def find_paths(root, required_sum):
        allPaths = []
        find_paths_recursive(root, required_sum, [], allPaths)
        return allPaths
      

      find_paths 中,allPaths 作为一个空列表传递给find_paths_recursive,完成后,它将包含结果(满足所述条件的从根到叶的路径)。

      【讨论】:

        【解决方案3】:

        我建议将问题分解为单独的部分。首先我们写一个通用的paths函数-

        def paths (t = None, p = ()):
          if not t:
            return
          elif t.left or t.right:
            yield from paths(t.left, (*p, t.val))
            yield from paths(t.right, (*p, t.val))
          else:
            yield (*p, t.val)
        
        mytree = TreeNode \
          ( 12
          , TreeNode(7, TreeNode(4))
          , TreeNode(1, TreeNode(10)) 
          )
        

        现在我们可以看到paths 是如何工作的 -

        for p in paths(mytree):
          print(p)
        
        (12, 7, 4)
        (12, 1, 10)
        

        现在我们可以写solver 专门用于paths -

        def solver (t = None, q = 0):
          for p in paths(t):
            if sum(p) == q:
              yield p
        

        solver 是一个生成器,它产生所有个可能的解决方案。对于这样的程序,这是一个不错的选择,因为您可以在找到您正在寻找的解决方案后立即暂停/取消解决方案 -

        for sln in solver(mytree, 23):
          print(sln)
        

        输出并不是特别有趣,因为mytree 中的每个分支总和为 23 -

        (12, 7, 4)
        (12, 1, 10)
        

        如果我们让anothertree 具有不同的值,我们可以看到更有趣的输出 -

        anothertree = TreeNode \
          ( 1
          , TreeNode(7, TreeNode(4), TreeNode(5))
          , TreeNode(9, TreeNode(2), TreeNode(7))
          )
        
        for sln in solver(anothertree, 12):
          print(sln)
        
        (1, 7, 4)
        (1, 9, 2)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-07-31
          • 1970-01-01
          • 1970-01-01
          • 2019-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多