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

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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值