LeetCode 第 437 题「路径总和 III」
字数 1024 2025-10-26 12:39:58

我来给你讲解 LeetCode 第 437 题「路径总和 III」。虽然它在你的列表中出现过,但根据你的要求,我将详细讲解它的描述和解题过程。


题目描述

给定一个二叉树的根节点 root,和一个整数 targetSum,求该二叉树里节点值之和等于 targetSum路径 的数目。

路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

示例
输入:root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出:3
解释:有 3 条路径的和等于 8:

  • 5 → 3
  • 5 → 2 → 1
  • -3 → 11

解题思路

步骤 1:理解路径的灵活性

路径不一定从根开始,也不一定到叶子结束,所以任意节点都可以作为路径的起点或终点。
关键:对于每个节点,我们考虑以它为终点的路径中,有多少条路径的和等于 targetSum


步骤 2:暴力法(DFS 双重递归)

最直接的方法是:

  1. 遍历每个节点(第一层递归)。
  2. 对于每个节点,计算以它为终点的路径和(第二层递归)。

代码框架

def pathSum(root, targetSum):
    if not root:
        return 0
    # 计算以当前节点为终点的路径数 + 左子树路径数 + 右子树路径数
    return dfs(root, targetSum) + pathSum(root.left, targetSum) + pathSum(root.right, targetSum)

def dfs(node, target):
    if not node:
        return 0
    count = 0
    if node.val == target:
        count += 1
    # 继续向左右子树搜索,但目标值变为 target - node.val
    count += dfs(node.left, target - node.val)
    count += dfs(node.right, target - node.val)
    return count

时间复杂度:O(n²),最坏情况每个节点都要遍历其子树。


步骤 3:优化思路(前缀和 + 回溯)

我们可以用 前缀和 来优化:

  • 在遍历树时,记录从根节点到当前节点的路径和 currSum
  • 如果存在一个之前的前缀和 prevSum 使得 currSum - prevSum = targetSum,那么从 prevSum 对应的节点到当前节点的路径和就是 targetSum

具体步骤

  1. 用一个哈希表 prefixSumCount 记录路径上每个前缀和出现的次数。
  2. 递归遍历二叉树,更新当前路径和 currSum
  3. 检查 currSum - targetSum 是否在哈希表中,如果在,说明存在路径。
  4. 递归左右子树。
  5. 回溯时,将当前路径和的前缀计数减一(避免影响其他分支)。

步骤 4:优化后的代码实现

def pathSum(root, targetSum):
    from collections import defaultdict
    prefixSumCount = defaultdict(int)
    prefixSumCount[0] = 1  # 空路径的前缀和为 0
    return dfs(root, 0, targetSum, prefixSumCount)

def dfs(node, currSum, target, prefixSumCount):
    if not node:
        return 0
    currSum += node.val
    # 查找符合条件的前缀和
    count = prefixSumCount[currSum - target]
    # 更新哈希表
    prefixSumCount[currSum] += 1
    # 递归左右子树
    count += dfs(node.left, currSum, target, prefixSumCount)
    count += dfs(node.right, currSum, target, prefixSumCount)
    # 回溯
    prefixSumCount[currSum] -= 1
    return count

时间复杂度:O(n),每个节点只遍历一次。
空间复杂度:O(n),哈希表和递归栈的空间。


总结

  • 暴力法:双重递归,直观但效率低。
  • 优化法:利用前缀和将问题转化为“两数之差”问题,通过哈希表快速查找,将时间复杂度降为 O(n)。

如果你对前缀和或回溯部分还有疑问,我可以进一步解释。

我来给你讲解 LeetCode 第 437 题「路径总和 III」 。虽然它在你的列表中出现过,但根据你的要求,我将详细讲解它的描述和解题过程。 题目描述 给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。 示例 输入: root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8 输出: 3 解释:有 3 条路径的和等于 8: 5 → 3 5 → 2 → 1 -3 → 11 解题思路 步骤 1:理解路径的灵活性 路径不一定从根开始,也不一定到叶子结束,所以任意节点都可以作为路径的起点或终点。 关键 :对于每个节点,我们考虑以它为终点的路径中,有多少条路径的和等于 targetSum 。 步骤 2:暴力法(DFS 双重递归) 最直接的方法是: 遍历每个节点(第一层递归)。 对于每个节点,计算以它为终点的路径和(第二层递归)。 代码框架 : 时间复杂度 :O(n²),最坏情况每个节点都要遍历其子树。 步骤 3:优化思路(前缀和 + 回溯) 我们可以用 前缀和 来优化: 在遍历树时,记录从根节点到当前节点的路径和 currSum 。 如果存在一个之前的前缀和 prevSum 使得 currSum - prevSum = targetSum ,那么从 prevSum 对应的节点到当前节点的路径和就是 targetSum 。 具体步骤 : 用一个哈希表 prefixSumCount 记录路径上每个前缀和出现的次数。 递归遍历二叉树,更新当前路径和 currSum 。 检查 currSum - targetSum 是否在哈希表中,如果在,说明存在路径。 递归左右子树。 回溯时,将当前路径和的前缀计数减一(避免影响其他分支)。 步骤 4:优化后的代码实现 时间复杂度 :O(n),每个节点只遍历一次。 空间复杂度 :O(n),哈希表和递归栈的空间。 总结 暴力法 :双重递归,直观但效率低。 优化法 :利用前缀和将问题转化为“两数之差”问题,通过哈希表快速查找,将时间复杂度降为 O(n)。 如果你对前缀和或回溯部分还有疑问,我可以进一步解释。