返回

揭秘破解LeetCode神技:掌握160、404、437,二叉树也能畅行无阻

见解分享

二叉树概述

二叉树是一种重要的数据结构,它由节点组成,每个节点至多有两棵子树,分别称为左子树和右子树。二叉树广泛应用于计算机科学的各个领域,例如查找、排序、存储和压缩等。

LeetCode题160:二叉树中和为给定值路径数目

题目

给定一个二叉树,它的每个结点都存放着一个整数值。找出路径和等于给定数值的路径总数。路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。

算法思路:

  • 递归法:该算法采用自顶向下的方式,递归地计算每个节点到所有子节点的路径和。当路径和等于给定值时,计数器加一。时间复杂度为O(n^2),其中n为树的节点数。

  • 动态规划法:该算法采用自底向上的方式,先计算每个节点到其子节点的路径和,然后逐步计算每个节点到其祖先节点的路径和。时间复杂度为O(n),空间复杂度为O(n)。

代码实现:

# 递归法
def path_sum(root, target_sum):
    if not root:
        return 0

    # 计算以当前节点为起点的路径和
    current_sum = root.val

    # 统计以当前节点为起点的路径和为target_sum的路径数
    path_count = 0
    if current_sum == target_sum:
        path_count += 1

    # 递归计算左右子树的路径和
    path_count += path_sum(root.left, target_sum - current_sum)
    path_count += path_sum(root.right, target_sum - current_sum)

    return path_count


# 动态规划法
def path_sum_dp(root, target_sum):
    # 创建一个字典,key为路径和,value为路径数
    path_sums = {0: 1}

    # 递归计算每个节点到其子节点的路径和
    def dfs(root, current_sum):
        if not root:
            return 0

        # 计算以当前节点为起点的路径和
        current_sum += root.val

        # 统计以当前节点为起点的路径和为target_sum的路径数
        path_count = path_sums.get(current_sum - target_sum, 0)

        # 更新字典中的路径和
        path_sums[current_sum] = path_sums.get(current_sum, 0) + 1

        # 递归计算左右子树的路径和
        path_count += dfs(root.left, current_sum)
        path_count += dfs(root.right, current_sum)

        # 撤销当前节点的路径和更新
        path_sums[current_sum] -= 1

        return path_count

    return dfs(root, 0)

LeetCode题404:左叶子之和

题目:

给定一个二叉树,计算所有左叶子之和。左叶子是指左子树没有子节点的叶子节点。二叉树不超过2000个节点,且节点数值范围是 [-1000000,1000000] 的整数。

算法思路:

  • 递归法:该算法采用自顶向下的方式,递归地遍历二叉树。当遇到左叶子节点时,将该节点的值添加到结果中。时间复杂度为O(n),其中n为树的节点数。

  • 深度优先搜索(DFS):该算法采用深度优先的方式,遍历二叉树。当遇到左叶子节点时,将该节点的值添加到结果中。时间复杂度为O(n),其中n为树的节点数。

  • 广度优先搜索(BFS):该算法采用广度优先的方式,遍历二叉树。当遇到左叶子节点时,将该节点的值添加到结果中。时间复杂度为O(n),其中n为树的节点数。

代码实现:

# 递归法
def sum_of_left_leaves(root):
    if not root:
        return 0

    # 计算左子树的左叶子之和
    left_sum = sum_of_left_leaves(root.left)

    # 计算右子树的左叶子之和
    right_sum = sum_of_left_leaves(root.right)

    # 如果当前节点是左叶子,则将当前节点的值添加到结果中
    if not root.left and not root.right:
        return root.val

    return left_sum + right_sum


# 深度优先搜索(DFS)
def sum_of_left_leaves_dfs(root):
    stack = [root]
    total_sum = 0

    while stack:
        # 弹出栈顶元素
        node = stack.pop()

        # 如果当前节点是左叶子,则将当前节点的值添加到结果中
        if node.left and not node.left.left and not node.left.right:
            total_sum += node.left.val

        # 将右子树压入栈中
        if node.right:
            stack.append(node.right)

        # 将左子树压入栈中
        if node.left:
            stack.append(node.left)

    return total_sum


# 广度优先搜索(BFS)
def sum_of_left_leaves_bfs(root):
    queue = [root]
    total_sum = 0

    while queue:
        # 弹出队列首元素
        node = queue.pop(0)

        # 如果当前节点是左叶子,则将当前节点的值添加到结果中
        if node.left and not node.left.left and not node.left.right:
            total_sum += node.left.val

        # 将右子树入队
        if node.right:
            queue.append(node.right)

        # 将左子树入队
        if node.left:
            queue.append(node.left)

    return total_sum

LeetCode题437:路径总和III

题目:

给定一个二叉树,它的每个结点都存放着一个整数值。找出路径和等于给定数值的路径总数。路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。

算法思路:

  • 递归法:该算法采用自顶向下的方式,递归地计算每个节点到所有子节点的路径和。当路径和等于给定值时,计数器加一。时间复杂度为O(n^2),其中n为树的节点数。

  • 动态规划法:该算法采用自底向上的方式,先计算每个节点到其子节点的路径和,然后逐步计算每个节点到其祖先节点的路径和。时间复杂度为O(n),空间复杂度为O(n)。

代码实现:

# 递归法
def path_sum(root, target_sum):
    if not root:
        return 0

    # 计算以当前节点为起点的路径和
    current_sum = root.val

    # 统计以当前节点为起点的路径和为target_sum的路径数
    path_count = 0
    if current_sum == target_sum:
        path_count += 1

    # 递归计算左右子树的路径和
    path_count += path_sum(root.left, target_sum - current_sum)
    path_count += path_sum(root.right, target_sum - current_sum)

    return path_count


# 动态规划法
def path_sum_dp(root, target_sum):
    # 创建一个字典,key为路径和,value为路径数