路径总和III——对前缀和解法的解释

本文详细介绍了如何运用前缀和解决二叉树中寻找路径和等于特定值的问题。通过理解前缀和的概念,利用HashMap记录路径和并恢复状态,将时间复杂度降低,避免暴力求解导致的效率低下。文章通过实例解析了前缀和在二叉树问题中的应用,并提供了关键代码实现。

目录

前言        

存在问题

一、前缀和的定义

二、为什么要用前缀和来解决此题

三、HashMap是用来干什么的

四、为什么要恢复状态

最终代码


前言        

        本文基于对学习前缀和遇到的问题和理解,总结下来;每个人的理解方式都有差异,希望可以帮到各位;


存在问题

        可能会在这些问题上纠结一些时间:

  • 前缀和的定义
  • 为什么要用前缀和来解决此题
  • HashMap是用来干什么的
  • 为什么要恢复状态

一、前缀和的定义

一句话概括就是:从该节点到某一节点的路径上,所有结点的val之和;

如下图(原题栗子):

解释:

        例如

        10 -> 5 -> 3 这条路径各节点val之和就是结点3的前缀和;

        10 -> 5 -> 2 -> 1这条路径各结点val之和就是结点1的前缀和;


二、为什么要用前缀和来解决此题

题目要求:

        我们在遍历二叉树的时候更容易拿到的是从根节点向下遍历得到的路径,而本题的要求是从某一结点出发,若是暴力解决的话,时间复杂度为O(n^2),无法通过,所以就可以通过前缀和来解决;

具体的,我们可以这样做:

这时,基于前面对前缀和定义的了解,不难理解:

两节点间的路径之和 = 结束结点的前缀和 - 开始结点的前缀和;

也就是说,假设f(x)函数表示前缀和,那么

两节点间的路径之和 = f(end) - f(start);

如下图:

解释:

        结点3的前缀和 = 1 + 3 = 4;

        结点7的前缀和 = 1 + 3 + 5 + 7 = 16;

        f(end) - f(start) = 12;

所以,结点3 到 结点7 有一条路径符合要求(5 - > 7);

这时,问题就转化了!!!,遍历整棵树的每一个结点,记录下每一个结点的前缀和,然后检测该结点的祖先结点中符合条件的个数,最后将满足要求的数量加到最终结果上;


三、HashMap是用来干什么的

        满足当前结点到祖先结点中路径之和等于k的路径,有可能不止一条路径(还可能有其他的祖先节点也满足),也就是说祖先节点中可能会有前缀和相同的俩个祖先结点 如下图:

解释:

        前缀和为1的结点:结点1, 结点0;

        所以路径和为5的结点有两条:

  • 0 - > 5;
  • 5本身;

HashMap用来记录前缀和相同的路径路径数量,key为前缀和,value是该前缀和的结点数量


四、为什么要恢复状态

        因为只能是从祖先结点到子结点,是向下的,所以在更新HashMap时,只对子节点有效;

如下图:

 当遍历到最左边的叶子结点4时,对于他来说,前缀和为4的只有结点A,没有B,因为B向下找不到叶子结点4;若不恢复状态,那么在遍历完左树后遍历到右树的叶子结点6时,他就会认为A,B都是满足要求的结点,而导致重复错误,所以,遍历完一个结点的子节点后,要将其从map中删掉;


最终代码

class Solution {
    private Map<Long, Integer> map = new HashMap<>();//保存前缀和
    private int target;
    public int pathSum(TreeNode root, int targetSum) {
        this.target = targetSum;
        map.put(0L, 1);//必须要有一个前缀和为0的
        return dfs(root, 0);
    }
    private int dfs(TreeNode root, long sum) {
        if(root == null) {
            return 0;
        }
        sum += root.val;
        //拿到需要的前缀和
        int request = map.getOrDefault(sum - target, 0);//需要的前缀和就是当前和减去目标
        //保存当前前缀树的值
        map.put(sum, map.getOrDefault(sum, 0) + 1);
        //递归看左右子树
        int left = dfs(root.left, sum);
        int right = dfs(root.right, sum);
        //恢复状态
        map.put(sum, map.get(sum) - 1);
        return left + right + request;//返回所有满足的
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈亦康

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值