刷刷刷 Day 18 | 路径总和

112. 路径总和

LeetCode题目要求

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。

图

示例

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。
解题思路

本地要计算的事从根节点到叶子节点路径的和是否符合targetSum,是不是想到了之前的 257. 二叉树的所有路径 这个题,那么是不是可以对这个题稍作修改,找到所有路径后来计算他们的和是否符合 targetSum。其实这样做的话,并不是太优,因为我们要找到所有路径。而本题其实只要找到其中一个符合的就可以,也就是不需要遍历出所有的路径。
那么本题可以采用前序遍历的方式,并不断的用 targetSum 减去节点值,当差为 0 且节点为叶子节点时就找到了

上代码

class Solution {
    public boolean hasPathSum(TreeNode node, int targetSum) {
        if (node == null) {
            return false;
        }

        targetSum -= node.val;

        // 叶子节点路径的和是否符合 targetSum
        if (node.left == null && node.right == null) {
            return targetSum == 0;
        }

        // 处理左子树,如果和符合 targetSum, 返回true
        if (node.left != null) {
            if (hasPathSum(node.left, targetSum)) {
                return true;
            }
        }

        // 处理右子树,如果和符合 targetSum, 返回true
        if (node.right != null) {
            if (hasPathSum(node.right, targetSum)) {
                return true;
            }
        }

        return false;
    }
}
重难点

前序遍历,递归,回溯。 这里回溯实际是隐藏了起来。可以通过 debug 模式来自己理解下


113. 路径总和 II

LeetCode题目要求

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。

图

示例

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]
解题思路

本题类似于 112. 路径总和。稍微复杂的是需要所有的路径,其实这个题可以采用这个题 257. 二叉树的所有路径 ,找到所有路径后来计算他们的和是否符合 targetSum,把符合的都输出就是结果了。

上代码

class Solution {

    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>> res = new ArrayList<>();

        List<Integer> paths = new ArrayList<>();
        traversal(root, targetSum, res, paths);

        return res;
    }

    private void traversal(TreeNode node, int targetSum, List<List<Integer>> res, List<Integer> paths) {
        if (node == null) {
            return;
        } 

        //前序遍历,先是中节点
        paths.add(node.val);

        // 是否叶子节点
        if (node.left == null && node.right == null) {
            // 如果符合目标值,需要将值放入到 结果集,由于需要找到过个路径,这里不能变化 targetSum 的值
            if (targetSum - node.val == 0) {
                res.add(new ArrayList<>(paths));
            }
            return;
        }

        if (node.left != null) {
            // 由于需要找到过个路径,这里不能变化 targetSum 的值
            traversal(node.left, targetSum - node.val, res, paths);
            // 回溯
            paths.remove(paths.size() - 1);
        }

        if (node.right != null) {
            // 由于需要找到过个路径,这里不能变化 targetSum 的值
            traversal(node.right, targetSum - node.val, res, paths);
            // 回溯
            paths.remove(paths.size() - 1);
        }
    }
}
重难点

前序遍历,递归,回溯。递归不需要返回值

附:学习资料链接

posted @ 2023-01-24 12:13  blacksonny  阅读(20)  评论(0编辑  收藏  举报