返回

二叉树的那些事儿:从根到叶的二进制数之和

后端

深度优先搜索:计算二叉树中的根到叶二进制数之和

引言

在计算机科学中,二叉树是一种重要的数据结构,用于组织和存储数据。解决二叉树问题时,深度优先搜索(DFS)是一种强大的算法,可以帮助我们有效地遍历和处理树结构。本文将探讨如何使用 DFS 来解决一个经典的二叉树问题:计算从根节点到叶节点的二进制数之和。

问题定义

给定一棵二叉树,其中每个节点的值要么是 0,要么是 1。我们定义一条路径从根节点开始,沿着树枝一直延伸到叶节点。我们可以用 0 和 1 组成的字符串来表示这条路径。例如,从根节点到叶节点的路径 1 -> 0 -> 1 -> 1 可以表示为字符串 "1011"。

二进制数之和

从根节点到叶节点的二进制数之和定义为这些路径字符串中所有数字的和。例如,路径 "1011" 的二进制数之和为 3(1 + 0 + 1 + 1)。

深度优先搜索(DFS)

DFS 是一种递归算法,它沿着树枝尽可能深地遍历树。当到达叶节点或无法进一步遍历时,DFS 会回溯到上一个节点,然后继续遍历下一条路径。在 DFS 中,我们通常使用一个栈来存储当前正在访问的节点。

解决方案

要计算二叉树中从根到叶的二进制数之和,我们可以使用 DFS 算法:

  1. 初始化 :将二进制数之和初始化为 0。
  2. 递归函数 :定义一个辅助函数 dfs(node, current_sum),其中 node 是当前正在访问的节点,current_sum 是从根节点到 node 的二进制数之和。
  3. 基线情况 :如果 node 为空,则返回。
  4. 计算二进制数之和 :将 node 的值左移一位,并与 current_sum 按位或运算,得到新的 current_sum
  5. 叶节点 :如果 node 是叶节点(即没有左右子树),则将 current_sum 添加到二进制数之和中。
  6. 递归调用 :对 node 的左子树和右子树递归调用 dfs() 函数。

代码示例

def sum_root_to_leaf(root):
  """
  计算二叉树中从根到叶的二进制数之和。

  参数:
    root: 二叉树的根节点

  返回值:
    二进制数之和
  """

  # 初始化二进制数之和为 0
  total_sum = 0

  def dfs(node, current_sum):
    # 如果当前节点为空,则返回
    if not node:
      return

    # 计算二进制数之和
    current_sum = (current_sum << 1) | node.val

    # 如果当前节点是叶节点,则将二进制数之和添加到总和中
    if not node.left and not node.right:
      total_sum += current_sum
      return

    # 递归调用左子树和右子树
    dfs(node.left, current_sum)
    dfs(node.right, current_sum)

  # 从根节点开始计算二进制数之和
  dfs(root, 0)

  # 返回总和
  return total_sum

复杂度分析

DFS 算法的时间复杂度为 O(n),其中 n 是二叉树中的节点数。DFS 需要访问每个节点一次,因此时间复杂度与节点数成正比。

结论

通过使用深度优先搜索,我们可以有效地计算二叉树中从根到叶的二进制数之和。这在解决各种计算机科学问题中是一个有用的技术,例如路径查找、状态空间搜索和图遍历。

常见问题解答

  1. DFS 和 BFS(广度优先搜索)有什么区别?

    • DFS 以深度优先的方式遍历树,而 BFS 以广度优先的方式遍历树。DFS 会沿着树枝尽可能深地遍历,而 BFS 会逐层遍历。
  2. DFS 适用于哪些问题?

    • DFS 适用于需要找到从一个节点到另一个节点的路径、判断图中是否有环或连通分量等问题。
  3. 为什么 DFS 的时间复杂度是 O(n)?

    • DFS 需要访问每个节点一次,而二叉树中的节点数为 n。因此,时间复杂度与节点数成正比。
  4. 如何使用 DFS 查找二叉树中的最长路径?

    • 使用 DFS 遍历二叉树,并保持到目前为止遇到的最长路径的长度。在访问每个节点时,更新最长路径的长度。
  5. 如何使用 DFS 判断二叉树是否是平衡二叉树?

    • 使用 DFS 遍历二叉树,并计算每个子树的高度。如果每个子树的高度差不超过 1,则二叉树是平衡二叉树。