【详细整理】437-路径总和|||

325 阅读2分钟

题目

给定一个二叉树,它的每个结点都存放着一个整数值。找出路径和等于给定数值的路径总数。路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。 二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。

思路

一、DFS前缀和加回溯

前缀和:(在树的情况)就是根节点到这个节点的路径和

因为提给要求不一定从根节点开始,所以找一个两节点路径和=target就是这俩节点之间的前缀和之差=target.所以就转换成了找一个节点它的前缀和:sum=presum-tagert.

注意点:

HashMap:来减少运行读取时间,key是前缀和, value是前缀和=key的节点数量

回溯:因为题目定义方向向下,所以只有同一条路径上的节点间(节点和其某一祖先节点间)的前缀和做差才有意义。所以当前节点处理完之后,需要从map中移除这一个前缀和,然后再进入下一个分支路径。 回溯就是在出递归之后做操作(撤销/移除选择)来维护递归有效性.

    // 定义一个全局变量来储存路径和=target的数量
    int res = 0;
    public int pathSum(TreeNode root, int targetSum) {
        // 创建HasMap来储存路径和
        HashMap<Integer,Integer> map = new HashMap<>();
        // 放入0,1是因为要有一个0值作为起点,便于后续路径和计算(节点值-0)
        map.put(0,1);      
        DFS(root,targetSum,map,0);
        // return DFS(root,targetSum,map,0);
        return res;
    }

// 实现功能是计算节点前缀和、同时放入map中,返回值为前缀和的值。在过程中求得路径和
    public int DFS(TreeNode root, int targetSum,HashMap<Integer,Integer> map,int sum ){
        if(root==null){
            return 0; 
        }
        // 求前缀和
        sum += root.val;
        // 从map中读取前缀和为sum-targetSum的节点数量,用res记录。
        res += map.getOrDefault(sum-targetSum,0);
        // 将这个节点前缀和放入对应key的统计部分
        map.put(sum,map.getOrDefault(sum,0)+1);
        // res += DFS(root.left,targetSum,map,sum);
        // res += DFS(root.right,targetSum,map,sum);
        // 遍历左右节点
        DFS(root.left,targetSum,map,sum);
        DFS(root.right,targetSum,map,sum);
        // 重点:因为题目规定路径方向向下,所以节点和其某一祖先节点间的前缀和做差才有意义,所以当前节点都处理完之后,要将它移除。
        map.put(sum,map.get(sum)-1);
        return sum;
        
    }
}

二、双递归

这种题目需要从每个节点开始进行类似的计算,所以第一个递归用来遍历这些节点,这二个递归用来处理这些节点,进行深度优先搜索。

class Solution { 
    int pathnumber;
    //遍历节点
    public int pathSum(TreeNode root, int sum) {
            if(root == null) return 0;            
            Sum(root,sum);
            pathSum(root.left,sum);
            pathSum(root.right,sum); 
            return pathnumber;
        }
        
    //处理节点
    public void Sum(TreeNode root, int sum){
        if(root == null) return;
        sum-=root.val;
        if(sum == 0){
            pathnumber++;           
        }
        Sum(root.left,sum);
        Sum(root.right,sum);
    } 
}`

时间复杂度很高,在计算SUM的时候也计算了下面,优化可以把左右子树拿出来。

    int pathnumber;
    
    public int pathSum(TreeNode root, int sum) {
            if(root == null) return 0;            
            Sum(root,sum);
        }
        
    public int path(TreeNode root, int sum){
        pathSum(root.left,sum);
        pathSum(root.right,sum);
        return pathnumber;
        
    }
    public void Sum(TreeNode root, int sum){
        if(root == null) return;
        sum-=root.val;
        if(sum == 0){
            pathnumber++;           
        }
        Sum(root.left,sum);
        Sum(root.right,sum);
    } 
}