夸父追日:第六章 二叉树 part04

今日收获:找树左下角的值,路径总和,从中序与后序遍历序列构造二叉树

1. 找树左下角的值

题目链接:513. - 力扣(LeetCode)

思路:每一层遍历前记录最左侧节点的值,然后再遍历该层节点,并把左右孩子加入队列中

方法:

class Solution {
    public int findBottomLeftValue(TreeNode root) {
        // 层次迭代遍历
        int result=0;
        Queue<TreeNode> queue=new LinkedList<>();
        
        if (root!=null){
            queue.offer(root);
        }

        while (!queue.isEmpty()){
            int len=queue.size();
            TreeNode left=queue.peek();  // 每一层的最左侧节点
            result=left.val;

            while(len>0){
                TreeNode temp=queue.poll();
                if (temp.left!=null){
                    queue.offer(temp.left);
                }
                if (temp.right!=null){
                    queue.offer(temp.right);
                }
                len--;
            }
        }

        return result;
    }
}

2. 路径总和

题目链接:112. - 力扣(LeetCode)

思路:和求所有路径那道题思路相似。如果是叶子节点计算节点之和,不是叶子节点就向下遍历,注意向下遍历结束后要回溯。

方法:

    List<Integer> path=new ArrayList<>();

    public boolean hasPathSum(TreeNode root, int targetSum) {
        if (root==null){
            return false;
        }

        path.add(root.val);
        // 叶子节点
        if (root.left==null&&root.right==null){
            return sumPath(path)==targetSum;
        }
        
        // 左右孩子
        boolean isLeft=false;
        if (root.left!=null){
            isLeft=hasPathSum(root.left,targetSum);
            path.remove(path.size()-1);
        }

        boolean isRight=false;
        if (root.right!=null){
            isRight=hasPathSum(root.right,targetSum);
            path.remove(path.size()-1);
        }

        return isLeft||isRight;
    }

    public int sumPath(List<Integer> path){
        int sum=0;
        for (int value:path){
            sum+=value;
        }
        return sum;
    }
}

相关题目:

113. - 力扣(LeetCode)

思路:

        1. 由于path是全局变量,所以需要在满足条件时添加此时的路径副本(还得是chatgpt,马上就发现了我的问题)

        2. 可以不用额外定义计算路径和的函数,只要在遍历左右子树时传入目标值减去当前节点的值

方法:

class Solution {
    List<Integer> path=new ArrayList<>();
    List<List<Integer>> result=new ArrayList<>();

    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        path(root,targetSum);
        return result;
    }

    public void path(TreeNode root,int targetSum){
        if (root==null){
            return;
        }

        path.add(root.val);
        // 叶子节点
        if (root.left==null&&root.right==null){
            if (sumPath(path)==targetSum){
                result.add(new ArrayList<>(path));
            }
        }
        
        // 左右孩子
        if (root.left!=null){
            path(root.left,targetSum);
            path.remove(path.size()-1);
        }

        if (root.right!=null){
            path(root.right,targetSum);
            path.remove(path.size()-1);
        }
    }

    public int sumPath(List<Integer> path){
        int sum=0;
        for (int value:path){
            sum+=value;
        }
        return sum;
    }
}

总结:注意Java的引用数据类型和全局变量。构造列表副本的方法。 

3. 从中序与后序遍历序列构造二叉树

题目链接:106. - 力扣(LeetCode)

思路:根据后序列表中最后一个值确定根节点,由根节点在中序数组中划分左右子树的中序列表,再根据左右子树长度确定左右子树的后序列表

方法:

class Solution { 
    // 便于在中序数组中根据值找位置
    Map<Integer,Integer> map=new HashMap<>();

    public TreeNode buildTree(int[] inorder, int[] postorder) {
        for(int i=0;i<inorder.length;i++){
            map.put(inorder[i],i);
        }

        return helper(inorder,0,inorder.length,postorder,0,postorder.length);
    }

    public TreeNode helper(int[] inorder,int inBegin,int inEnd,int[] postorder,int postBegin,int postEnd){
        if (inBegin>=inEnd||postBegin>=postEnd){
            return null;
        }

        int rootval=postorder[postEnd-1];
        TreeNode root=new TreeNode(rootval);

        // 划分中序数组
        int rootIndex=map.get(postorder[postEnd-1]);
        int leftNum=rootIndex-inBegin;

        // 左右孩子
        root.left=helper(inorder,inBegin,inBegin+leftNum,postorder,postBegin,postBegin+leftNum);
        root.right=helper(inorder,rootIndex+1,inEnd,postorder,postBegin+leftNum,postEnd-1);

        return root;
    }
}

总结:

        1. 前序和中序、后序和中序一定可以确定一颗二叉树

        2. 保持循环不变量原则,数组保持左闭右开

        3. 利用map集合存储中序列表中的值和对应位置,方便划分左右子树的长度。

相关题目

105. - 力扣(LeetCode)从前序与中序遍历序列构造二叉树

思路:和106题不同的是,前序列表中第一个节点是根节点,再根据此节点划分。注意递归的数组长度,区间是左闭右开

方法: 

class Solution {
    // 便于在中序数组中根据值找位置
    Map<Integer,Integer> map=new HashMap<>();

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        for(int i=0;i<inorder.length;i++){
            map.put(inorder[i],i);
        }

        return helper(inorder,0,inorder.length,preorder,0,preorder.length);
    }

    public TreeNode helper(int[] inorder,int inBegin,int inEnd,int[] preorder,int preBegin,int preEnd){
        if (inBegin>=inEnd||preBegin>=preEnd){
            return null;
        }

        int rootval=preorder[preBegin];
        TreeNode root=new TreeNode(rootval);

        // 划分中序数组
        int rootIndex=map.get(rootval);
        int leftNum=rootIndex-inBegin;

        // 左右孩子
        root.left=helper(inorder,inBegin,inBegin+leftNum,preorder,preBegin+1,preBegin+leftNum+1);
        root.right=helper(inorder,rootIndex+1,inEnd,preorder,preBegin+leftNum+1,preEnd);

        return root;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值