题目
输入一颗二叉树的根节点和一个整数,按字典序打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。如图所示:
思路
我的思路是递归:递归方法是返回当前路径下匹配目标值的路径。
共有几种情况:
- 当节点为空,return
- 当和大于目标值,return
- 当和等于目标值 并且 节点下无其他节点
节点下无其他节点说明是叶子节点,并且路径值的和满足了目标值,添加到结果中 并且return - 当和小于目标值,继续递归
遇到的坑
- 第一眼看到这道题的时候以为是传统意义上的深度优先遍历,但是仔细想想便知道简单的深度优先遍历并不能解决问题:深度优先遍历是遍历的每一个节点,而这道题要求的是返回一个二维数组,二维数组中的一位数组存放的是符合要求的路径,那么必须涉及到“回溯”的问题,例如当图中10-5-4路径不符合目标值时,我们需要返回4的上一个节点5,进而继续遍历5的右子树7。
- 路径的定义:从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。
- 递归函数并不一定要返回数组类型,可以使用引用传递来改变参数的值。
遇到坑后的反思
由于涉及到“回溯”的问题,这里想到了两个办法解决这个问题
- 每遍历一个新的节点便开辟一个新的一维数组(ArrayList),这样便避免了回溯的问题,因为当遇到10-5-4这样的情况,并不需要回到5节点,而只需要将这种情况产生的数组排除即可,但是这种情况的空间复杂度较高。
- 使用栈。由于栈的先入后出规则,当4压栈时,判断路径与target不符合,那么将4出栈,将7压栈,这种方法空间复杂度较低。
开辟数组方法的代码(每次递归开辟一个新的数组)
import java.util.ArrayList;
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
ArrayList<ArrayList<Integer>> path = new ArrayList<ArrayList<Integer>>();//path作为返回值
ArrayList<Integer> temp = new ArrayList<Integer>();
Stack<Integer> Final = new Stack<>();
AddPath(root,target,0,temp, path);//递归中修改path的值
return path;
}
private void AddPath (TreeNode root,int target, int sum,ArrayList<Integer> temp, ArrayList<ArrayList<Integer>> path){
if(root == null || sum + root.val > target) return;//当root为空或者总和大于target,不修改path
if(root.left == null && root.right == null){//当遍历到叶子节点
if(root.val + sum == target){
temp.add(root.val);
path.add(temp);//修改path值
}
return;//如果加上叶子节点小于target,返回
}
temp.add(root.val);//当既不是叶子节点,也没有大于target时,继续添加当前值
if(root.left != null){
AddPath(root.left,target,sum+root.val,(ArrayList<Integer>)temp.clone(),path);//一定要用clone()来开辟一个新的temp
}
if(root.right != null){
AddPath(root.right,target,sum+root.val,(ArrayList<Integer>)temp.clone(),path);
}
}
}
代码反思
- root.val不能盲目地直接加在sum上,因为不知道当前的root是否在最后符合条件的路径中
- 一定要用clone()来开辟一个新的temp
使用栈的代码
未完待续…