34.二叉树中和为某一值的路径

本文探讨了如何使用深度优先搜索(DFS)和二叉树的前缀和概念解决两个关于查找和为目标值的路径问题。首先,通过递归和双端队列找出所有和为给定整数的路径;接着,介绍了如何利用前缀和计数哈希表来快速计算满足条件的路径数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

34. 二叉树中和为某一值的路径

1 题目描述

​ 输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。

示例:给定如下二叉树,以及目标target=22,

              5
             / \
            4   8
           /   / \
          11  13  4
         /  \    / \
        7    2  5   1
返回
[
   [5,4,11,2],
   [5,8,4,5]
]

2 题目分析

​ 根据题意,我们要返回每一条从根节点到叶子节点和为target的路径,很容易想到dfs和双端队列。对于当前节点,先用target减去当前节点的值,将当前节点加入到路径中,然后递归判断其左子树和右子树是否有和为target-当前值的路径。碰到叶子节点,将叶子节点弹出。

3 代码

List<List<Integer>> ans = new LinkedList<>();
// 定义一个栈用来弹出叶子节点操作
Deque<Integer> path = new LinkedList<>();
public List<List<Integer>> pathSum(TreeNode root, int target) {
    dfs(root, target);
    return ans;
}

private void dfs(TreeNode root, int target) {
    if (root == null) return;

    // 由于是打印从根节点的路径,因此不能用栈的属性,push方法是往双端队列首部添加,我们要往尾部添加
    // 因此要用add或者offer或者offerLast
    path.offerLast(root.val);
    target -= root.val;
    // 判断是否是叶子节点
    if (root.left == null && root.right == null && target == 0) {
        // 找到一条路径
        ans.add(new LinkedList<Integer>(path));
    }
    dfs(root.left, target);
    dfs(root.right, target);
    // 将双端队列的尾部元素移除
    path.pollLast();
}

4 扩展:(力扣第437题)

4.1 前缀和概念

​ 不了解前缀和的先看一下前缀和的概念前缀和,这篇文章中介绍了一维和二维情况下的前缀和的应用场景,而下面这道题离谱到了对二叉树的前缀和使用。

4.2 题目描述

​ 给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

示例:

在这里插入图片描述

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

4.3 题目分析

​ 创建二叉树的前缀和形式如下图所示:
在这里插入图片描述

​ 从上图中我们就可以轻松知道一条路径中和为target的子路径有多少个,只需在前缀和二叉树中找当前的前缀和curSum-target出现的个数num即可,这个num就是以当前节点作为子序列的最后一个元素的和为target的路径个数。

​ 注意上面我们要找的是个数,相信到这里很多同学都会想到哈希表的数据结构,是的,对于节点我们用HashMap去存储它本身和出现的次数;而我们是用递归的思想去实现的,因此当当前节点左右子树都遍历完后需要在哈希表中删除当前节点(即对应的value减1),思路有了代码就很容易了。

4.4 代码

public int pathSum(TreeNode root, int targetSum) {
    if (root == null) return 0;
    // 初始化前缀和
    Map<Integer, Integer> prefixSumCount = new HashMap<>();
    prefixSumCount.put(0, 1);
    return recursionPathSum(root, prefixSumCount, targetSum, 0);
}

/*
	递归构建前缀和
*/
private int recursionPathSum(TreeNode root, Map<Integer, Integer> prefixSumCount, int targetSum, int currSum) {
    // 递归出口
    if (root == null) return 0;

    int count = 0;  // 初始化个数
    currSum += root.val;  // 计算当前节点的前缀和
    // 判断currSum-targetSum在map中出现的次数,更新count
    count += prefixSumCount.getOrDefault(currSum - targetSum, 0);
    // 更新map
    prefixSumCount.put(currSum, prefixSumCount.getOrDefault(currSum, 0) + 1);

    // 遍历左右子树
    count += recursionPathSum(root.left, prefixSumCount, targetSum, currSum);
    count += recursionPathSum(root.right, prefixSumCount, targetSum, currSum);
    
    // 回溯
    prefixSumCount.put(currSum, prefixSumCount.get(currSum) - 1);
    return count;
}
JZ34题目要求我们 在给定的二叉树找出所有为指定路径。这道题是JZ24二叉树中和为某路径的加强版,因为它需要我们找出所有符合要求的路径,而不是从根节点到叶节点路径。 我们可以采用深度优先遍历(DFS)的方法来解决这个问题。具体做法如下: 1. 首先我们需要定义一个函数,用于遍历二叉树: ```python def dfs(node, target, path, result): # node表示当前遍历的节点 # target表示剩余的目标 # path表示当前已选择的路径 # result表示符合要求的路径列表 # 如果遍历到了空节点,直接返回 if not node: return # 把当前节点添加到路径中 path.append(node.val) # 计算当前剩余的目标 target -= node.val # 如果目标为0,说明找到了条符合要求的路径,将其加入结果列表中 if target == 0 and not node.left and not node.right: result.append(path[:]) # 继续递归遍历左右子树 dfs(node.left, target, path, result) dfs(node.right, target, path, result) # 回溯,将刚刚添加的节点路径中删除 path.pop() ``` 2. 然后我们需要遍历整个二叉树,对于每个遍历到的节点,都调用次`dfs`函数,将其作为先前路径中的部分,并且更新`target`的: ```python def find_path(root, target): result = [] dfs(root, target, [], result) return result ``` 这样,我们就可以得到所有符合要求的路径了。 总之,这道题需要我们具备二叉树基础知识DFS基础知识,我们需要仔细阅读题目并思考,再将自己的思路转化为代码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值