Java——二叉树递归遍历练习(复杂逻辑Leecode257/113/129)

这一篇将介绍一些相对复杂的二叉树递归遍历逻辑,相对于上一篇较难。但是如果很好地理解了递归遍历的思想,也很容易找到解题思路。

Leecode257 找出二叉树的所有路径

在这里插入图片描述
1.判断递归结束条件:当节点为叶子结点,就可以返回该节点值对应的String集合。否则一直递归调用。
2.递归查找左子树的子路径,当前节点连接左子树中所有子路径,就是当前节点所有路径。
3.递归查找右子树的子路径,当前节点连接右子树中所有子路径,就是当前节点所有路径。
最后返回路径集合。

class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        List<String> list = new ArrayList<String>();
        if(root==null) return list;
        if(root.left==null&&root.right==null){
            list.add(Integer.toString(root.val));
            return list;
        }
        List<String> leftlist = binaryTreePaths(root.left);
        for(int i=0;i<leftlist.size();i++){
            list.add(Integer.toString(root.val)+"->"+leftlist.get(i));
        }
        List<String> rightlist = binaryTreePaths(root.right);
        for(int i=0;i<rightlist.size();i++){
            list.add(Integer.toString(root.val)+"->"+rightlist.get(i));
        }
        return list;
    }
}

Leecode113 路径求和

在这里插入图片描述
构造一个辅助函数,记录走过的路程。当走过的路程到达根节点,则将改路程存入list中返回,相应的路程回溯将当前节点去除。
每到达一个节点,都要存储;每返回一次都要进行当前节点退出路径操作。

class Solution {
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        List<List<Integer>> list = new ArrayList<>();
        if(root == null ) return list;
        Stack<Integer> stack = new Stack<Integer>();
        dfs(root,sum,stack,list);
        return list;
    }
    public void dfs(TreeNode node, int sum, Stack<Integer> path, List<List<Integer>> list){
        if(node==null) return ;
        //结束条件,是叶子且值相等,将当前路径添加到list中
        if(node.left==null&&node.right==null&&node.val==sum){
            path.add(node.val);
            //list.add(path);这么写返回全是null
            list.add(new ArrayList(path));
            path.pop();
        }
        path.push(node.val);//添加当前几点再计算
        dfs(node.left,sum-node.val,path,list);
        dfs(node.right,sum-node.val,path,list);
        path.pop();//在递归返回时,将当前节点去除
    }
}

Leecode129 跟到叶子节点数字之和

在这里插入图片描述
利用上一题的思想:把每条路径记录在list中。返回给主函数,在主函数中遍历list集合进行累加。
(不建议)

public int sumNumbers(TreeNode root) {
    List<String> list = binaryTreePaths(root);
    int sum = 0;
    for(int i= 0;i<list.size();i++){
        int s= Integer.parseInt(list.get(i));
        sum+=s;
    }
    return sum;
}
public List<String> binaryTreePaths(TreeNode root) {
    List<String> list = new ArrayList<String>();
    if(root==null) return list;
    if(root.left==null&&root.right==null){
        list.add(Integer.toString(root.val));
        return list;
    }
    List<String> leftlist = binaryTreePaths(root.left);
    for(int i=0;i<leftlist.size();i++){
        list.add(Integer.toString(root.val)+""+leftlist.get(i));
    }
    List<String> rightlist = binaryTreePaths(root.right);
    for(int i=0;i<rightlist.size();i++){
        list.add(Integer.toString(root.val)+""+rightlist.get(i));
    }
    return list;
}

上面的复杂度太大啦。看一下运用遍历三步法思考。
设置一个变量记录所有数据之和sum。
1.结束条件:为叶子结点则返回当前路径的数据,与sum相加。
2.每次向下递归都是数据增加十倍的过程,所以将上一层传递过来的数据*10+当前值;
3.递归左子树;
4.递归右子树;
(容易理解)

class Solution {
    private int sum = 0;
    private void helper(TreeNode node, int father) {
        if (node == null) return ;
        int current = father * 10 + node.val;
        if (node.left == null && node.right == null) {
            sum += current;
            return;
        }
        helper(node.left, current);
        helper(node.right, current);
    }

    public int sumNumbers(TreeNode root) {
        if (root == null) return sum;
        helper(root, 0);
        return sum;
    }
}

这个稍微难理解,没向下一层数据扩大。找到根节点就全部相加。

 public int sumNumbers(TreeNode root) {
        return helper(root, 0);
    }
    public int helper(TreeNode root, int i){
        if (root == null) return 0;
        int temp = i * 10 + root.val;
        if (root.left == null && root.right == null)
            return temp;
        return helper(root.left, temp) + helper(root.right, temp);
    }

通过非递归实现:
注意:1.二叉树的前序遍历非递归实现通过栈stack来实现;
2.二叉树的层次遍历通过队列queu来实现;
先序遍历
在访问节点的同时,记录走到当前节点的值。当为叶子结点时,sum求和。

class Solution {
    private int sum = 0;
    public int sumNumbers(TreeNode root) {
       if(root==null) return 0;
       Stack<TreeNode> stacknode = new Stack<TreeNode>();
       Stack<Integer> stack = new Stack<Integer>();
       stacknode.push(root);
       stack.push(0);
       while(!stacknode.isEmpty()){
           TreeNode node = stacknode.pop();
           int cur = stack.pop();
           if(node.left==null&&node.right==null){
               int temp = cur*10+node.val;
               sum+=temp;
           }
           if(node.left!=null){
                stacknode.push(node.left);
                stack.push(cur*10+node.val);
           }   
           if(node.right!=null){
               stacknode.push(node.right);
               stack.push(cur*10+node.val);
           }                
       }
       return sum;
    }    
}

层次遍历
在访问节点的同时,记录走到当前节点的值。要注意与层次遍历的不同,此处需要记录层次关系。因为层次关系影响着数值的倍数关系,所以每次入栈都需要保证一层入栈后再进行下一层的操作,所以添加了一次while循环,控制每次存取都以层为单位。当为叶子结点时,sum求和。

class Solution {
    private int sum = 0;
    public int sumNumbers(TreeNode root) {
       if(root==null) return 0;
        Queue<TreeNode> que = new LinkedList<TreeNode>();
        Queue<Integer> num = new LinkedList<Integer>();
        que.add(root);
        num.add(0);
        while(!que.isEmpty()){
            //由于涉及到层次对数据*10倍的影响,所以一次讲这一层的所有节点遍历完成并记住其对应的值
            int size = que.size();
            while(size-->0){
                TreeNode node = que.poll();
                int cur = num.poll()*10+node.val;
                if(node.left==null&&node.right==null)
                    sum+=cur;
                if(node.left!=null){
                    que.add(node.left);
                    num.add(cur);
                }
                if(node.right!=null){
                    que.add(node.right);
                    num.add(cur);
                }
            }
        }
        return sum;
    }
}

更复杂的一些逻辑:

Leecode437 路径三

在这里插入图片描述
在这个题目中,与简单的路径计算不同。没有强调必须是从根节点到叶子结点的一条路径,也就是说这条路径可以从半路开始从半路结束。
相比较原来从跟到叶子结点的路径计算逻辑更复杂,重新来分析:
1.当前节点在路径中,那么只需要查找到当前节点在几个路径中,递归的过程需要传递sum-node.val.
2.当前节点不在路径中,那么在递归调用时,传递的值为sum。

class Solution {
    public int pathSum(TreeNode root, int sum) {
        if(root==null) return 0;
        int res = finpath(root,sum);//当前节点在路径中
        res+=pathSum(root.left,sum);//当前节点不在路径中
        res+=pathSum(root.right,sum);
        return res;

    }
    public int finpath(TreeNode node,int sum){
        if(node==null) return 0;
        int res = 0;
        //不需要是叶子结点,所以遇到相等的值就+1。
        //考虑一条路径可能存在子路径。所以不能直接返回1,而应该计数。
        if(sum==node.val){
           res++;
        }
        res+=finpath(node.left,sum-node.val);
        res+=finpath(node.right,sum-node.val);
        return res;
    }
}
发布了16 篇原创文章 · 获赞 0 · 访问量 557

猜你喜欢

转载自blog.csdn.net/sunlili_yt/article/details/105368205