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


    目录

    前言        

    存在问题

    一、前缀和的定义

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

    三、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中删掉;


    最终代码

    1. class Solution {
    2. private Map map = new HashMap<>();//保存前缀和
    3. private int target;
    4. public int pathSum(TreeNode root, int targetSum) {
    5. this.target = targetSum;
    6. map.put(0L, 1);//必须要有一个前缀和为0的
    7. return dfs(root, 0);
    8. }
    9. private int dfs(TreeNode root, long sum) {
    10. if(root == null) {
    11. return 0;
    12. }
    13. sum += root.val;
    14. //拿到需要的前缀和
    15. int request = map.getOrDefault(sum - target, 0);//需要的前缀和就是当前和减去目标
    16. //保存当前前缀树的值
    17. map.put(sum, map.getOrDefault(sum, 0) + 1);
    18. //递归看左右子树
    19. int left = dfs(root.left, sum);
    20. int right = dfs(root.right, sum);
    21. //恢复状态
    22. map.put(sum, map.get(sum) - 1);
    23. return left + right + request;//返回所有满足的
    24. }
    25. }


  • 相关阅读:
    java基于SpringBoot+Vue的大学生体质健康测试管理系统 element
    ICMPv6基本理论讲解
    AI大模型使用(七)-模型微调与流式生成
    Jenkins + 云效 前后端项目自动化部署
    OpenCloudOS 助力趣丸科技降本增效,容器化高效运行
    PyTorch深度学习基础之Tensor对象及其应用的讲解及实战(附源码 简单易懂 包括分段 映射 矩阵乘法 随机数等等)
    tar.xz 文件的压缩和生成
    UE5 虚幻引擎 如何使用构造脚本(Construction Script)? 构造脚本的奥秘!
    Thinkphp下载oss文件至本地压缩包
    Unity 游戏设计模式:单例模式
  • 原文地址:https://blog.csdn.net/CYK_byte/article/details/127818226