vlambda博客
学习文章列表

二叉树(十六)--二叉树中和为某一值的路径

来源:LeetCode

难度:中等

描述:

        输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。


示例1:

        给定如下二叉树,以及目标和 target = 22

        返回:

        

二叉树(十六)--二叉树中和为某一值的路径



分析:

        本题的要求是,让我们找到所有满足从「根节点」到某个「叶子节点」经过的路径上的节点之和等于目标和的路径。

        因此我们需要对树进行遍历,并且在遍历时记录从根节点到当前节点的路径。此处介绍两种解法,具体步骤如下:


解题

方法一:深度优先遍历法

思路:

        采用深度优先遍历的方式,枚举每一条从根节点到叶子节点的路径。当我们遍历到叶子节点,且此时target和当前节点值一致时,我们就找到了一条满足条件的路径。

        注意,我们遍历完左右子树后,需要将记录的本节点从路径中删除


代码:

 1public List<List<Integer>> pathSum(TreeNode root, int target) {
2    if (root == null) {
3        return new ArrayList<>();
4    }
5    List<List<Integer>> ansList = new ArrayList<>();
6    //路径数组
7    List<Integer> pathList = new ArrayList<>();
8    findTargetPath(root, target, ansList, pathList);
9    return ansList;
10}
11private void findTargetPath(TreeNode root, int target, 
12                            List<List<Integer>> ansList, List<Integer> pathList)
 
{
13    if (root == null) {
14        return;
15    }
16    //本节点存入数组
17    pathList.add(root.val);
18    //target减去本节点
19    target -= root.val;
20    if (target == 0 && root.left == null && root.right == null) {
21        //target减去本节点为0 且本节点刚好为叶子节点,找到一条路径
22        ansList.add(new ArrayList<>(pathList));
23    }
24    //递归左右子树
25    findTargetPath(root.left, target, ansList, pathList);
26    findTargetPath(root.right, target, ansList, pathList);
27    //回溯、删除本节点
28    pathList.remove(pathList.size() - 1);
29}

时间复杂度:O(n * n) n为节点个数

空间复杂度:O(n) 


方法二:父节点记录法

思路:

        首先,咱们遍历一次二叉树,采用hash表记录每个节点和父节点的映射关系。同时,将父节点的值与本节点的值求和作为本节点的新值

        之后,遍历hash中的每个节点,如果该节点的值和target一致,且其左右节点为空,表明该节点为符合要求的叶子节点。根据hash表,找到该节点到根节点的路径即可


代码:

 1private void buildNode2Father(TreeNode root, 
2                              Map<TreeNode, TreeNode> node2Father)
 
{
3    if (root == null) {
4        return;
5    }
6    //root节点就是父节点,将其左右子节点指向它即可
7    if (root.left != null) {
8        //将父节点的值与本节点的值求和作为本节点的新值
9        root.left.val = root.left.val + root.val;
10        node2Father.put(root.left, root);
11        //处理左子树为父节点的情况
12        buildNode2Father(root.left, node2Father);
13    }
14    if (root.right != null) {
15        //将父节点的值与本节点的值求和作为本节点的新值
16        root.right.val = root.right.val + root.val;
17        node2Father.put(root.right, root);
18        //处理右子树为父节点的情况
19        buildNode2Father(root.right, node2Father);
20    }
21}
22
23
24public List<List<Integer>> pathSum(TreeNode root, int target) {
25    if (root == null) {
26        return new ArrayList<>();
27    }
28    List<List<Integer>> ansList = new ArrayList<>();
29    //路径数组
30    List<Integer> pathList = new ArrayList<>();
31    findTargetPath(root, target, ansList, pathList);
32    return ansList;
33}
34private void findTargetPath(TreeNode root, int target,
35                            List<List<Integer>> ansList, List<Integer> pathList)
 
{
36    if (root == null) {
37        return;
38    }
39    //本节点存入数组
40    pathList.add(root.val);
41    //target减去本节点
42    target -= root.val;
43    if (target == 0 && root.left == null && root.right == null) {
44        //target减去本节点为0 且本节点刚好为叶子节点,找到一条路径
45        ansList.add(new ArrayList<>(pathList));
46    }
47    //递归左右子树
48    findTargetPath(root.left, target, ansList, pathList);
49    findTargetPath(root.right, target, ansList, pathList);
50    //回溯、删除本节点
51    pathList.remove(pathList.size() - 1);
52}

时间复杂度:O(n * n) n为节点个数

空间复杂度:O(n) 


以上仅是个人思路解法,觉得还不错欢迎点赞关注分享


往期精彩推荐


算法和数据结构
IT程序员日常算法、数据结构分享
90篇原创内容
Official Account