【LeetCode】Day146-路径总和 III

题目

437. 路径总和 III【中等】

题解

相似题目:
112.路径总和【简单】
113. 路径总和 II【中等】
 
这两题所求路径都是根到叶子节点的,本题既不要求路径从根节点开始,也不要求在叶子节点结束

DFS

class Solution {
    public int pathSum(TreeNode root, int targetSum) {
        if(root==null)
            return 0;
        int res=rootSum(root,targetSum);//从root开始的路径
        res+=pathSum(root.left,targetSum);//从root左子开始的路径
        res+=pathSum(root.right,targetSum);//从root右子开始的路径
        return res;
    }
    public int rootSum(TreeNode root,long targetSum){
        if(root==null)
            return 0;
        int res=0;
        long value=root.val;//要用long型,不然有些用例过不了
        if(value==targetSum)
            res++;
        res+=rootSum(root.left,targetSum-value);
        res+=rootSum(root.right,targetSum-value);
        return res;
    }
}

时间复杂度: O ( n 2 ) O(n^2) O(n2),对于每一个节点,求以该节点为起点的路径数目时,则需要遍历以该节点为根节点的子树的所有节点,因此求该路径所花费的最大时间为 O(n),我们会对每个节点都求一次以该节点为起点的路径数目,因此时间复杂度为 O ( n 2 ) O(n^2) O(n2)

空间复杂度: O ( n ) O(n) O(n)

前缀和

仔细想想,方法一中其实有很多重复计算,比如计算以root为起点的路径时会计算到以其左子为起点的路径,计算以其左子为起点的路径时同样会计算到该路径。
为了改进方法一,我们定义节点的前缀和为:由根结点到当前结点的路径上所有节点的和。

算法
对二叉树进行先序遍历,

  1. 预先保存空路径,前缀和为0;
  2. 假设当前访问节点为node,root到node路径为root->p1->p2->…->pk->node,此时已经保存了p1,p2,…,pk的前缀和,并且计算出node的前缀和
  3. 假设node前缀和为curr,此时在已保存的前缀和中查找是否有前缀和==curr-targetSum。如果pi的前缀和符合要求,则p{i+1}到node的路径和一定为targetSum;
  4. 退出当前节点时,及时更新已经保存的前缀和。

注意
由于我们只能统计往下的路径,但是树的遍历会同时搜索两个方向的子树。因此我们应当在搜索完以某个节点为根的左右子树之后,应当回溯地将路径总和从哈希表中删除,防止统计到跨越两个方向的路径。

class Solution {
    Map<Long,Integer>prefix=new HashMap<>();//存储前缀和以及对应数量
    public int pathSum(TreeNode root, int targetSum) {
        prefix.put(0L,1);//'0L'代表强制把0转换为long型,否则0默认按int型处理
        return dfs(root,0,targetSum);
    }
    public int dfs(TreeNode root,long curr,long targetSum){
        if(root==null)
            return 0;
        int res=0;
        curr+=root.val;//更新前缀和
        res=prefix.getOrDefault(curr-targetSum,0);//计算curr-targetSum数量
        prefix.put(curr,prefix.getOrDefault(curr,0)+1);//保存当前节点前缀和

        res+=dfs(root.left,curr,targetSum);
        res+=dfs(root.right,curr,targetSum);

        prefix.put(curr,prefix.getOrDefault(curr,0)-1);//回溯
        return res;
    }
}

时间复杂度: O ( n ) O(n) O(n),利用前缀和只需遍历一次二叉树即可

空间复杂度: O ( n ) O(n) O(n)

最后可以看下两种方法的执行用时,差距还是挺大的
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值