LeetCode算法题(Go语言实现)_36

题目

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

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

一、代码实现(双重递归法)

go 复制代码
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 := 0
    if node.Val == remain {
        count++
    }
    // 递归处理左右子树,更新剩余目标值
    count += dfs(node.Left, remain - node.Val)
    count += dfs(node.Right, remain - node.Val)
    return count
}

二、算法分析(递归法)

1. 核心思路
  • 双重递归结构:外层递归遍历所有节点作为路径起点,内层递归计算以该节点为起点的路径数目
  • 暴力穷举:对每个节点及其子树进行深度优先搜索,统计符合条件的路径
2. 关键步骤
  1. 外层递归:遍历每个节点作为可能的路径起点
  2. 内层递归 :以当前节点为起点,向下搜索满足sum=targetSum的路径
  3. 终止条件:空节点返回0,当前节点值等于剩余值时计数+1
  4. 状态传递 :将剩余值remain - node.Val传递给子树
3. 复杂度
指标 说明
时间复杂度 O(n²) 每个节点触发一次O(n)的子树遍历
空间复杂度 O(h) h为树高度(递归栈空间)

三、代码实现(前缀和优化法)

go 复制代码
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.Val
    count := 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. 关键步骤
  1. 初始化哈希表 :预存prefixSum[0]=1处理根节点自身满足条件的情况
  2. 更新当前和 :累加节点值到currSum
  3. 查询差值 :计算currSum - target的出现次数
  4. 回溯操作:维护哈希表状态避免子树间的干扰
3. 复杂度
指标 说明
时间复杂度 O(n) 单次遍历所有节点
空间复杂度 O(n) 哈希表存储n个节点的前缀和

五、图解示例

root = [10,5,-3,3,2,null,11], targetSum=8为例:

复制代码
        10
       /  \
      5   -3
     / \    \
    3   2   11

前缀和法流程

  1. 路径10→5→3:和为18 → 18-8=10(无记录)
  2. 路径10→5→2:和为17 → 17-8=9(无记录)
  3. 路径10→5:和为15 → 15-8=7(无记录)
  4. 路径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最长路径
  • 三维路径:推广到三叉树等复杂结构
  • 流式处理:支持无法完整加载内存的超大树结构
相关推荐
zh_xuan24 分钟前
LeeCode92. 反转链表II
数据结构·算法·链表·leecode
2401_841495641 小时前
【数据结构】汉诺塔问题
java·数据结构·c++·python·算法·递归·
Q741_1471 小时前
C++ 位运算 高频面试考点 力扣137. 只出现一次的数字 II 题解 每日一题
c++·算法·leetcode·面试·位运算
天特肿瘤电场研究所1 小时前
专业的肿瘤电场疗法厂家
算法
DASXSDW2 小时前
NET性能优化-使用RecyclableBuffer取代RecyclableMemoryStream
java·算法·性能优化
kfepiza2 小时前
CAS (Compare and Swap) 笔记251007
java·算法
墨染点香2 小时前
LeetCode 刷题【103. 二叉树的锯齿形层序遍历、104. 二叉树的最大深度、105. 从前序与中序遍历序列构造二叉树】
算法·leetcode·职场和发展
啊我不会诶2 小时前
23ICPC澳门站补题
算法·深度优先·图论
sitellla3 小时前
Testify Go测试工具包入门教程
git·测试工具·其他·golang
Brookty3 小时前
【算法】二分查找(一)朴素二分
java·学习·算法·leetcode·二分查找