584 字
3 分钟
路径总和 III

题目描述#

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

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

解题思路#

  1. 双重DFS
    • 外层DFS遍历所有节点作为路径起点
    • 内层DFS计算以当前节点为起点的路径和
  2. 前缀和优化
    • 哈希表记录路径前缀和出现次数
    • 当前前缀和 - targetSum 查表获得有效路径数
  3. 回溯维护:递归时更新哈希表,回溯时恢复状态
  4. 边界处理:初始化哈希表 {0:1} 处理根节点自身满足条件的情况

关键洞察#

  1. 子问题分解:任意节点都可作为路径起点或中间点
  2. 前缀和原理当前和 - targetSum = 历史前缀和 即存在有效路径
  3. 哈希表加速:将O(n²)暴力搜索优化为O(n)查询
  4. 回溯必要性:确保哈希表仅记录当前路径的前缀和
  5. 空路径初始化{0:1}处理路径正好等于targetSum的情况

复杂度分析#

  • 时间复杂度
    • 暴力DFS:O(n²)
    • 前缀和+DFS:O(n)
  • 空间复杂度O(n)
    • 递归栈O(h) + 哈希表O(n)(h为树高)

代码实现#

/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @param {number} targetSum
* @return {number}
*/
var pathSum = function (root, targetSum) {
if (!root) return 0;
// 初始化前缀和映射表(前缀和 -> 出现次数)
const prefixSum = new Map();
prefixSum.set(0, 1); // 关键:空路径前缀和为0
let count = 0;
const dfs = (node, currentSum) => {
if (!node) return;
// 计算当前节点前缀和
currentSum += node.val;
// 检查是否存在有效路径:当前和 - targetSum = 历史前缀和
const prevSum = currentSum - targetSum;
count += prefixSum.get(prevSum) || 0;
// 更新当前前缀和的计数
prefixSum.set(currentSum, (prefixSum.get(currentSum) || 0) + 1);
// 递归遍历子树
dfs(node.left, currentSum);
dfs(node.right, currentSum);
// 回溯:移除当前节点贡献的前缀和
prefixSum.set(currentSum, prefixSum.get(currentSum) - 1);
};
dfs(root, 0);
return count;
};

相似题目#

路径总和 III
https://website-truelovings-projects.vercel.app/posts/algorithms/路径总和-iii/
作者
欢迎来到StarSky的网站!
发布于
2025-08-07
许可协议
CC BY-NC-SA 4.0