LeetCode437.路径总和III

news/2024/7/20 20:58:57 标签: 深度优先, 算法, leetcode, java

 看完题目我就拿直接用递归写了如下代码:

java">class Solution {
    private int ans;
    public int pathSum(TreeNode root, int targetSum) {
            ans =0;
            dfs(root, targetSum, 0);
            return ans;
    }
    public void dfs(TreeNode root, int targetSum, int sum){
        if(root == null)return;
        sum += root.val;
        if(sum == targetSum)ans++;
        dfs(root.left, targetSum, sum);
        dfs(root.left, targetSum, 0);
        dfs(root.right, targetSum, sum);
        dfs(root.right, targetSum, 0);
        return;
    }
}

 dfs方法中的参数sum表示从前面某个节点到上一个节点的和,拿这个sum加上当前节点的值如果等于targetSum那么答案数+1,然后可以把现在的sum往下面传递,也可以传一个0下去表示从下一个节点开始计算和,然后示例过了,测试用例没过,因为这样的话重复计算了多个答案,比如一个全右的树1,2,3,4,5,target=3,那么在dfs1的时候,传了sum等于0,然后dfs2的时候又传了sum等于0,然后dfs3,这条1,2,3的路径给算进去了,所以这样是不行的。然后自己想了一会没思路就直接看了题解,

题解的第一种做法用的就是深度优先,但和我的不一样,他用了两层递归

首先定义第一个递归方法:

java">public int rootSum(TreeNode root, int targetSum)

它表示以root为起点的路径中,和为target的个数。在主函数中递归遍历每个节点,把这些节点的rootSum加起来。以下是方法一的代码:

java">class Solution {
    public int pathSum(TreeNode root, int targetSum) {
            if(root == null)return 0;
            int ans =0;
            ans+=rootSum(root,targetSum);
            ans+= pathSum(root.left, targetSum);
            ans+=pathSum(root.right, targetSum);
            return ans;
    }
    public int rootSum(TreeNode root, long targetSum){
        if(root == null)return 0;
        int ret = 0;
        if(root.val == targetSum) ret++;
        ret+= dfs(root.left, targetSum-root.val);
        ret+= dfs(root.right, targetSum-root.val);
        return ret;
    }
}

在rootSum()方法中要算以root为起点和为targetSum的路径数,就是算以root.left为起点和为targetSum-root.val的路径数加上以root.right为起点,和为targetSum-root.val的路径数。当root.val=targetSum时+1。然后主函数递归遍历每个节点,使得每个节点都调用一遍rootSum()方法。

方法一的时间复杂度时O(n2)很高,做了很多重复的计算。方法二是利用了HashMap里面存放前缀和来减少遍历次数。以下是方法二代码:

java">class Solution {
    public int pathSum(TreeNode root, int targetSum) {
        Map<Long, Integer> prefix = new HashMap<Long, Integer>();
        prefix.put(0L, 1);
        return dfs(root, prefix, 0, targetSum);
    }

    public int dfs(TreeNode root, Map<Long, Integer> prefix, long curr, int targetSum) {
        if (root == null) {
            return 0;
        }

        int ret = 0;
        curr += root.val;

        ret = prefix.getOrDefault(curr - targetSum, 0);
        prefix.put(curr, prefix.getOrDefault(curr, 0) + 1);
        ret += dfs(root.left, prefix, curr, targetSum);
        ret += dfs(root.right, prefix, curr, targetSum);
        prefix.put(curr, prefix.getOrDefault(curr, 0) - 1);

        return ret;
    }
}

Map<Long, Integer> prefix里面存的是,路径和为key的数量value,long curr表示从根节点到当前节点的和,这一点必须明白。

假如根节点是root,我们正在访问的节点是node,这条路径就是root->p1->p2->..->pk..->node。计算到node的时候从root到node的和是curr,那么我们只要找到前面的一个节点pk,它的curr1是curr-targetNum,那么从pk到node的和就是tagetNum。我们不需要找到这个pk,只需要知道这条路径上有多少个这样的pk就行。所以我们的HashMap中存放的是和为key的数量而不是节点。

理解了这个看dfs方法就比较容易了。

java">ret = prefix.getOrDefault(curr - targetSum, 0);

这个HashMap的getOrDefault方法是先去get这个key这里是curr-targetSum。如果没有这个key就返回默认值这里是0。这样就拿到了以当前节点为终点和为target的路径的数量,

java">prefix.put(curr, prefix.getOrDefault(curr, 0) + 1);

然后再把从root到当前节点的和放进map里面,然后递归遍历子节点。因为这个prefix的map是全局都在用的,所以当你把当前节点遍历完了你得回溯,把自己给移出去,因为递归回到前面的时候,前面的节点不能用后面节点的前缀和,所以要把这个前缀和的数量-1。


http://www.niftyadmin.cn/n/5241916.html

相关文章

文件已过期或已被清理怎么恢复?3个宝藏方法分享!

“我今天清理电脑时才发现有部分文件已经过期无法查看了&#xff0c;但是其中有些文件是比较重要的&#xff0c;这可怎么办呢&#xff1f;这些被清理的文件还有恢复的可能吗&#xff1f;” 在我们的日常工作中&#xff0c;可能会遇到文件已过期或已被清理的情况&#xff0c;这通…

深度探索大数据分析:挖掘价值与洞察力

目录 写在开头1. 导论1.1 大数据的定义与特征1.2 大数据对业务和决策的影响1.3 大数据分析的基本原则2. 大数据技术与工具2.1 分布式计算框架2.2 数据存储与管理2.3 大数据处理与分析工具3. 数据采集与清洗3.1 数据源的多样性3.2 数据采集工具与技术3.3 数据清洗与预处理的重要…

技术博客:Vue中各种混淆用法汇总

技术博客&#xff1a;Vue中各种混淆用法汇总 摘要 本文主要介绍了在Vue中使用的一些常见混淆用法&#xff0c;包括new Vue()、export default {}、createApp()、Vue.component、Vue3注册全局组件、Vue.use()等&#xff0c;以及如何使用混淆器对代码进行加固&#xff0c;保护应…

Hadoop学习笔记(HDP)-Part.19 安装Kafka

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

【C++】:set和map

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关多态的知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结…

C/c++源代码qt软件 svn版本管理开发如何防泄密?

现在很多研发团队采用的是c/c语言&#xff0c;版本管理服务器采用的是svn&#xff0c;开发工具qt软件或vc软件&#xff0c;或是matlab等开发工具&#xff0c;对于这种环境&#xff0c;安秉网盾有完善的防泄密方案&#xff0c;支持各种研发环境。 员工本地电脑防泄密场景 文件…

深入理解 Queue 队列:数据结构与应用场景解析

大家好&#xff0c;我是香香。 前段时间我们提到了 Collection 容器中的 List、Set&#xff1b;还有独立于 Collection 容器的 Map&#xff08;K-V&#xff09;集合。 今天我们来深入探讨 Java 中的 Queue 队列&#xff0c;另一个继承于 Collection 容器的接口&#xff1a;Queu…

阻碍“元宇宙”游戏行业发展的最大瓶颈是什么?

很显然&#xff0c;我们现在还没看到真正的“元宇宙”产品&#xff0c;在3-5年内也不太可能看到这样的产品。按照米哈游CEO蔡浩宇的说法&#xff0c;2030年希望建成一个“上亿人愿意生活在其中的虚拟世界”&#xff0c;那也是八年以后的事情了。 原因很简单&#xff1a;技术不成…