题目描述
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
a. 代码的主要思想即树的先序递归遍历,用一个arraylist来记录根节点到当前节点的路径。
b.
c.
d. 使用target递减的方式,是一个巧妙的小心思。因为可以把比较的过程直接放在遍历过程中进行。不必等到访问到叶子节点,再次对当前路径的值求和。
e. 有不少网友疑问,“栈回退以后,target不需要重新加回退节点的值吗?” 针对这个疑问,答案是不需要添加。其原理是,每次递归时,当前变量的值都会重新拷贝一份儿,进入到下次遍历中。也就是说,当前遍历过程中的各个变量值,会被保存到当前的环境中。当前遍历结束,各个变量被销毁,不会影响到回退的遍历。即遍历压栈是将当前环境压栈。
public
class
Solution {
private
ArrayList<ArrayList<Integer>> listAll =
new
ArrayList<ArrayList<Integer>>();
private
ArrayList<Integer> list =
new
ArrayList<Integer>();
public
ArrayList<ArrayList<Integer>> FindPath(TreeNode root,
int
target) {
if
(root ==
null
)
return
listAll;
list.add(root.val);
target -= root.val;
if
(target ==
0
&& root.left ==
null
&& root.right ==
null
)
listAll.add(
new
ArrayList<Integer>(list));
FindPath(root.left, target);
FindPath(root.right, target);
list.remove(list.size()-
1
);
return
listAll;
}
}
b.
list.remove(list.size()-1)
这句话是模拟了栈回退。当前节点为叶子节点或者已经访问过的情况下,回溯到父节点。
c.
listAll.add(new ArrayList<Integer>(list))
这个细节要注意,必须要重新生成一个对象实例,并使用list对其初始化赋值。不可以直接listAll.add(list),因为list本质上是引用,在各次遍历中会直接改变它的值,最后的路径集合中前面的路径也会被后面的覆盖。再次强调这种做法是错误的。
d. 使用target递减的方式,是一个巧妙的小心思。因为可以把比较的过程直接放在遍历过程中进行。不必等到访问到叶子节点,再次对当前路径的值求和。
e. 有不少网友疑问,“栈回退以后,target不需要重新加回退节点的值吗?” 针对这个疑问,答案是不需要添加。其原理是,每次递归时,当前变量的值都会重新拷贝一份儿,进入到下次遍历中。也就是说,当前遍历过程中的各个变量值,会被保存到当前的环境中。当前遍历结束,各个变量被销毁,不会影响到回退的遍历。即遍历压栈是将当前环境压栈。