找回密码
 立即注册
首页 业界区 安全 剑指offer-80、⼆叉树中和为某⼀值的路径(二) ...

剑指offer-80、⼆叉树中和为某⼀值的路径(二)

洪思思 7 小时前
题⽬描述

给定⼀个⼆叉树root和⼀个整数值 sum ,求该树有多少路径的的节点值之和等于 sum 。

  • 该题路径定义不需要从根节点开始,也不需要在叶⼦节点结束,但是⼀定是从⽗亲节点往下到孩⼦节点
  • 总节点数⽬为 n
  • 保证最后返回的路径个数在整形范围内
假如⼆叉树 root 为 {1,2,3,4,5,4,3,#,#,-1} , sum=6 ,那么总共如下所示,
1.png

思路及解答

双重递归法(暴力解法)

外层递归遍历所有节点作为起点,内层递归计算从该点向下的路径和
  1. public class Solution {
  2.     public int pathSum(TreeNode root, int targetSum) {
  3.         if (root == null) return 0;
  4.         
  5.         // 以当前节点为起点的路径数 + 左右子树的路径数
  6.         return countPaths(root, targetSum) +
  7.                pathSum(root.left, targetSum) +
  8.                pathSum(root.right, targetSum);
  9.     }
  10.    
  11.     /**
  12.      * 计算以当前节点为起点的路径数
  13.      */
  14.     private int countPaths(TreeNode node, long targetSum) {
  15.         if (node == null) return 0;
  16.         
  17.         int count = 0;
  18.         
  19.         // 如果当前节点值等于目标值,找到一条路径
  20.         if (node.val == targetSum) {
  21.             count++;
  22.         }
  23.         
  24.         // 递归计算左右子树
  25.         count += countPaths(node.left, targetSum - node.val);
  26.         count += countPaths(node.right, targetSum - node.val);
  27.         
  28.         return count;
  29.     }
  30. }
复制代码

  • 时间复杂度:O(n²),最坏情况下每个节点都要递归遍历其子树
  • 空间复杂度:O(n),递归栈深度
前缀和哈希表(最优解)

从根节点到当前节点的路径和curSum,查找curSum-targetSum是否存在
前缀和核心思想:

  • 路径和 = 当前前缀和 - 之前某个前缀和
  • curSum - targetSum是否存在于前缀和哈希表中
  • 如果存在,说明从那个节点到当前节点的路径和为targetSum
执行示例(树[10,5,-3,3,2,null,11,3,-2,null,1],sum=8):
  1. 从根到节点3:前缀和=10+5+3=18
  2. targetSum=8 → 查找18-8=10是否存在
  3. 哈希表中有10(根节点)→ 找到路径:5->3
复制代码
  1. import java.util.HashMap;
  2. public class Solution {
  3.     public int pathSum(TreeNode root, int targetSum) {
  4.         // 哈希表存储前缀和及其出现次数
  5.         HashMap<Long, Integer> prefixSum = new HashMap<>();
  6.         prefixSum.put(0L, 1); // 初始前缀和为0,出现1次
  7.         
  8.         return dfs(root, 0, targetSum, prefixSum);
  9.     }
  10.    
  11.     private int dfs(TreeNode node, long curSum, int targetSum,
  12.                     HashMap<Long, Integer> prefixSum) {
  13.         if (node == null) return 0;
  14.         
  15.         // 计算从根节点到当前节点的前缀和
  16.         curSum += node.val;
  17.         
  18.         // 查找前缀和中是否存在curSum - targetSum
  19.         // 如果存在,说明从那个节点到当前节点的路径和为targetSum
  20.         int count = prefixSum.getOrDefault(curSum - targetSum, 0);
  21.         
  22.         // 将当前前缀和加入哈希表
  23.         prefixSum.put(curSum, prefixSum.getOrDefault(curSum, 0) + 1);
  24.         
  25.         // 递归处理左右子树
  26.         count += dfs(node.left, curSum, targetSum, prefixSum);
  27.         count += dfs(node.right, curSum, targetSum, prefixSum);
  28.         
  29.         // 回溯:移除当前前缀和,避免影响其他分支
  30.         prefixSum.put(curSum, prefixSum.get(curSum) - 1);
  31.         
  32.         return count;
  33.     }
  34. }
复制代码

  • 时间复杂度:O(n),每个节点只访问一次
  • 空间复杂度:O(n),哈希表存储n个前缀和
记忆化递归法

使用记忆化技术缓存计算结果,为每个节点存储从该节点向下的路径和计数,优化递归效率。
  1. import java.util.HashMap;
  2. public class Solution {
  3.     public int pathSum(TreeNode root, int targetSum) {
  4.         return pathSumHelper(root, targetSum, new HashMap<>());
  5.     }
  6.    
  7.     private int pathSumHelper(TreeNode node, int targetSum,
  8.                               HashMap<TreeNode, Integer> memo) {
  9.         if (node == null) return 0;
  10.         
  11.         // 如果结果已缓存,直接返回
  12.         if (memo.containsKey(node)) {
  13.             return memo.get(node);
  14.         }
  15.         
  16.         // 计算以当前节点为起点的路径数
  17.         int count = countFromNode(node, targetSum, 0);
  18.         
  19.         // 递归计算左右子树
  20.         count += pathSumHelper(node.left, targetSum, memo);
  21.         count += pathSumHelper(node.right, targetSum, memo);
  22.         
  23.         // 缓存结果
  24.         memo.put(node, count);
  25.         
  26.         return count;
  27.     }
  28.    
  29.     private int countFromNode(TreeNode node, int targetSum, long currentSum) {
  30.         if (node == null) return 0;
  31.         
  32.         currentSum += node.val;
  33.         int count = 0;
  34.         
  35.         if (currentSum == targetSum) {
  36.             count++;
  37.         }
  38.         
  39.         count += countFromNode(node.left, targetSum, currentSum);
  40.         count += countFromNode(node.right, targetSum, currentSum);
  41.         
  42.         return count;
  43.     }
  44. }
复制代码

  • 时间复杂度:O(n),每个节点计算一次
  • 空间复杂度:O(n),缓存所有节点结果

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册