剑指Offer_#34_二叉树中和为某一值的路径

剑指Offer_#34_二叉树中和为某一值的路径

Contents

题目

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

示例:
给定如下二叉树,以及目标和 sum = 22,

              5
             / \
            4   8
           /   / \
          11  13  4
         /  \    / \
        7    2  5   1

返回:

[
   [5,4,11,2],
   [5,8,4,5]
]

提示:
节点总数 <= 10000

思路分析

这一题要寻找和是某一值的路径,所以代码需要做两件事。

  1. 遍历所有的路径
    • 深度优先遍历,前序遍历(根-左-右),采用递归写法
    • 这里需要借助一个类似于的结构来实现,因为每一次遍历到树的叶节点之后,需要回溯到父节点,继续遍历其他的叶节点,也就是需要把最后加入的一个叶节点弹出(后进先出)。但是这里需要把整个容器的所有数字都写入res,所以我们采用LinkedList
  2. 记录每一条路径的值的和,如果刚好到路径末尾了,且当前的和就是目标值,将其加入res列表
    • 在每一次访问到一个节点时,要把当前节点的值加到一个记录的变量当中

解答

写法1:递减

class Solution {
    LinkedList<List<Integer>> res = new LinkedList<>();
    LinkedList<Integer> path = new LinkedList<>();    
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        recur(root,sum);
        return res;
    }
    void recur(TreeNode root,int tar){
        //出口条件:遍历到叶节点
        if(root == null) return;
        //将当前节点的值加入到path当中
        path.add(root.val);
        tar -= root.val;
        if(tar == 0 && root.left == null && root.right == null)
            //为什么这里需要new?
            //path是全局变量,把当前的path对象内容拷贝到一个新的对象中,否则,res当中加入的path之后会发生变化
            res.add(new LinkedList(path));
        recur(root.left, tar);
        recur(root.right, tar);
        //这是LinkedList特有的方法,所以path初始化的时候,左边必须写成是LinkedList才能调用这个方法
        path.removeLast();
    }
}

注意recur()方法当中递归调用之前的几个语句的顺序。
一种有瑕疵的写法:

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> pathSum(TreeNode root, int target) {
        List<Integer> path = new ArrayList<>();
        recur(root, target, path);
        return res;
    }

    private void recur(TreeNode root, int target, List<Integer> path){
        if(target == 0) res.add(new ArrayList(path));
        if(root == null) return;
        path.add(root.val);
        recur(root.left, target - root.val, path);
        recur(root.right, target - root.val, path);
        path.remove(path.size() - 1);
    }
}

这么写会导致同一个路径被打印两次,具体原因可以自己在纸上画一下递归调用栈,模拟一遍。
正确解法相当于对于终止条件做了控制,使得最后只打印一次。

写法2:累加

class Solution {
    LinkedList<Integer> path= new LinkedList<>();
    LinkedList<List<Integer>> res = new LinkedList<>();
    int sum;
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        this.sum = sum;
        recur(root,0);
        return res;
    }

    void recur(TreeNode node, int curSum){
        if(node == null) return;
        curSum += node.val;
        path.add(node.val);
        if(curSum == sum && node.left == null && node.right == null)
            res.add(new LinkedList(path));
        recur(node.left,curSum);
        recur(node.right,curSum);
        path.removeLast();
    }
}
posted @ 2020-07-09 17:31  Howfar's  阅读(164)  评论(0编辑  收藏  举报