题目
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
一、代码实现(双重递归法)
func pathSum(root *TreeNode, targetSum int) int {if root == nil {return 0}// 计算以当前节点为起点的路径数 + 左右子树的路径数return dfs(root, targetSum) + pathSum(root.Left, targetSum) + pathSum(root.Right, targetSum)
}func dfs(node *TreeNode, remain int) int {if node == nil {return 0}count := 0if node.Val == remain {count++}// 递归处理左右子树,更新剩余目标值count += dfs(node.Left, remain - node.Val)count += dfs(node.Right, remain - node.Val)return count
}
二、算法分析(递归法)
1. 核心思路
- 双重递归结构:外层递归遍历所有节点作为路径起点,内层递归计算以该节点为起点的路径数目
- 暴力穷举:对每个节点及其子树进行深度优先搜索,统计符合条件的路径
2. 关键步骤
- 外层递归:遍历每个节点作为可能的路径起点
- 内层递归:以当前节点为起点,向下搜索满足
sum=targetSum
的路径 - 终止条件:空节点返回0,当前节点值等于剩余值时计数+1
- 状态传递:将剩余值
remain - node.Val
传递给子树
3. 复杂度
指标 | 值 | 说明 |
---|---|---|
时间复杂度 | O(n²) | 每个节点触发一次O(n)的子树遍历 |
空间复杂度 | O(h) | h为树高度(递归栈空间) |
三、代码实现(前缀和优化法)
func pathSum(root *TreeNode, targetSum int) int {prefixSum := make(map[int]int)prefixSum[0] = 1 // 处理根节点自身满足条件的情况return dfs(root, 0, targetSum, prefixSum)
}func dfs(node *TreeNode, currSum int, target int, prefixSum map[int]int) int {if node == nil {return 0}currSum += node.Valcount := prefixSum[currSum - target]prefixSum[currSum]++count += dfs(node.Left, currSum, target, prefixSum)count += dfs(node.Right, currSum, target, prefixSum)prefixSum[currSum]-- // 回溯return count
}
四、算法分析(前缀和法)
1. 核心思路
- 前缀和哈希表:记录从根节点到当前节点的路径和出现次数
- 数学关系:若存在
currSum - target = oldSum
,则oldSum -> currSum
的路径和为target
2. 关键步骤
- 初始化哈希表:预存
prefixSum[0]=1
处理根节点自身满足条件的情况 - 更新当前和:累加节点值到
currSum
- 查询差值:计算
currSum - target
的出现次数 - 回溯操作:维护哈希表状态避免子树间的干扰
3. 复杂度
指标 | 值 | 说明 |
---|---|---|
时间复杂度 | O(n) | 单次遍历所有节点 |
空间复杂度 | O(n) | 哈希表存储n个节点的前缀和 |
五、图解示例
以root = [10,5,-3,3,2,null,11], targetSum=8
为例:
10/ \5 -3/ \ \3 2 11
前缀和法流程:
- 路径
10→5→3
:和为18 → 18-8=10(无记录) - 路径
10→5→2
:和为17 → 17-8=9(无记录) - 路径
10→5
:和为15 → 15-8=7(无记录) - 路径
10→-3→11
:和为18 → 18-8=10(命中初始0)
最终计数:3(路径5→3、路径5→2→1、路径-3→11)
六、边界条件与扩展
1. 特殊场景验证
- 空树:返回0
- 负数和零:如
root = [-2,null,-3], target=-5
→ 返回1 - 重复路径:多节点值相同的情况需正确计数
2. 扩展应用
- 多条件路径统计:同时满足和值与节点数限制
- 动态目标值:支持实时修改targetSum的在线查询
- 路径回溯:记录具体路径而非仅计数(需维护路径栈)
七、总结与优化方向
1. 方法对比
方法 | 优势 | 劣势 | 适用场景 |
---|---|---|---|
双重递归 | 实现简单 | 时间复杂度高 | 小规模树(n<1000) |
前缀和 | 线性时间复杂度 | 需要维护哈希表状态 | 大规模树 |
2. 工程优化
- 并行计算:对左右子树进行并发遍历(Go协程)
- 内存预分配:根据树高度预判哈希表容量
- 数值溢出处理:使用int64存储累加和
3. 算法扩展
- K路径问题:统计和值为targetSum的TopK最长路径
- 三维路径:推广到三叉树等复杂结构
- 流式处理:支持无法完整加载内存的超大树结构