算法题型总结 求二叉树路径和

文章介绍了在LeetCode中涉及的路径总和问题系列,包括使用DFS方法解决112、113和437题,以及如何利用前缀和和Map优化124题的二叉树最大路径和。还提到了124题的变种,路径定义排除了兄弟节点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 以下题目均整理自力扣,由易到难,掌握以下题目,基本对该类题型有一个深刻的理解;求解本类题目的基本套路是DFS

112.路径总和

class Solution {
    boolean flag;
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if(root==null) return false;
        dfs(root,0,targetSum);
        return flag;
    }

    void dfs(TreeNode root,int sum,int targetSum){
        if(root.left==null && root.right==null){
            flag |= (sum + root.val == targetSum);
            return;
        }
        if(root.left!=null) dfs(root.left,sum+root.val,targetSum);
        if(root.right!=null) dfs(root.right,sum+root.val,targetSum);
    }
}

113.路径总和 II

class Solution {
    // 前缀和
    // 思路: 记录前缀和到一个map中,只要 preSum - targetSum目标值 在map中存在
    // 就说明存在符合targetSum的路径
    List<List<Integer>>ans = new ArrayList<>();
    List<Integer> temp = new ArrayList<>();
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        if(root==null) return ans;
        dfs(root,0,targetSum,new ArrayList<Integer>());
        return ans;
    }

    // 整个过程temp都是引用同一个,所以在返回上一层的时候需要回溯
    void dfs(TreeNode root,int sum,int targetSum,List<Integer>temp){
        if(root.left==null && root.right==null){
            if(sum + root.val == targetSum){
                temp.add(root.val);
                ans.add(new ArrayList<>(temp));
                // 返回上一层的时候需要回溯
                temp.remove(temp.size()-1);
            }
            return;
        }
        temp.add(root.val);
        if(root.left!=null) dfs(root.left,sum+root.val,targetSum,temp);
        if(root.right!=null) dfs(root.right,sum+root.val,targetSum,temp);
        // 返回上一层的时候需要回溯!
        temp.remove(temp.size()-1);
    }
}

437.路径总和 III

这里用到map、前缀和来记录 路径和等于target的数量,这个解法真不容易想到、
如果 前缀和减去target得到的结果如果存在于map中,说明存在路径和为target的路径
参考题解: . - 力扣(LeetCode)

这个题还有个坑,后面有个case数很大,导致计算前缀和会发生溢出,影响到最终计算的结果,所以需要把Map的key换成Long类型,对应的case为:[1000000000,1000000000,null,294967296,null,1000000000,null,1000000000,null,1000000000]

class Solution {
    int ans;
    // k:前缀和 v: 存在该前缀和的数量
    // 测试case中存在结点val值很大的情况,所以用Long类型
    Map<Long,Integer> map = new HashMap<>();
    public int pathSum(TreeNode root, int targetSum) {
        // 前缀和为0需要特殊处理,否则如果存在前缀和为targetSum的
        // 那么就会错失从根结点到当前结点的这条路径
        map.put(0L,1);

        dfs(root,targetSum,0);
        return ans;
    }

    void dfs(TreeNode root,int targetSum,long preSum){
        if(root==null) return;
        preSum += root.val;
        // 如果preSum-targetSum 在map中存在,表示存在和为target的路径
        ans += map.getOrDefault(preSum-targetSum,0);
        map.put(preSum,map.getOrDefault(preSum,0)+1);
        dfs(root.left,targetSum,preSum);
        dfs(root.right,targetSum,preSum);
        // 返回上一层,就不包含该结点了,需要把经过该结点的前缀和-1
        map.put(preSum,map.get(preSum)-1);
        // 这里preSum不需要回溯
    }
}

124.二叉树中的最大路径和

这题最多是mid,不是hard级别(不过太久了我又不会写了。。)

class Solution {
    int max = Integer.MIN_VALUE;
    public int maxPathSum(TreeNode root) {
        if(root.left == null && root.right == null) return root.val;
        dfs(root);
        return max;
    }


    // 返回以当前结点为根结点的树的权重和
    int dfs(TreeNode root) {
        if (root == null) return 0;
        // 左子树的和
        int left = dfs(root.left);
        // 右子树的和
        int right = dfs(root.right);
        max = Math.max(left+right+root.val, max);
        
        // 如果以root结点得到的权重和为小于0,则不应该加上去
        return Math.max(Math.max(left,right)+root.val,0);
    }
}

这是一条路径:

这也是一条路径:

这个就不是一条路径

二叉树的最大路径和II

修改下路径的定义,从根节点往左或往右构成的路径,不能出现兄弟节点
public class T124_maxPathSumII {

    @Test
    public void test() {
        Integer[] nums = new Integer[]{3, -2, 1, null, 4};
        TreeNode root = TreeNode.buildTree(nums);
        System.out.println(maxPathSum(root));
    }

    int max = Integer.MIN_VALUE;

    public int maxPathSum(TreeNode root) {
        dfs(root);
        return max;
    }

    public int dfs(TreeNode root) {
        if (root == null) return 0;
        int left = dfs(root.left);
        int right = dfs(root.right);
        max = Math.max(Math.max(left, right) + root.val, max);
        return Math.max(Math.max(left, right) + root.val, 0);
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值