[Day18]二叉树

69 阅读4分钟

今日内容:513.找树左下角的值、112.路经总和、113.路经总和||、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树 代码随想录链接:代码随想录 (programmercarl.com)

513.找树左下角的值

给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。

找到最后一行然后返回最左边的值。

用层序遍历做,当最后一层的时候返回最左边的元素。找到最后一层,然后输出第一个。

class Solution {
    public int findBottomLeftValue(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int res = root.val;
        while(!queue.isEmpty()){
            int len = queue.size();
            List<Integer> list = new ArrayList<>();
            while(len-- > 0){
                TreeNode cur = queue.poll();
                list.add(cur.val);
                if(cur.left != null)queue.offer(cur.left);
                if(cur.right != null)queue.offer(cur.right);
            }
            res = list.get(0);        
        }
        return res;
    }
}

这题取最后一行反而还方便了,到最后这个res队列保存的就是最后一行的值。这个时候返回第一个值就好了。

遍历法

用遍历的话,需要知道当前层是不是最后一层,因此需要传递深度。

class Solution {
    public int depth = 0;
    public int res;
    public int findBottomLeftValue(TreeNode root) {
        res = root.val;
        find(root,0);
        return res;
    }

    private void find(TreeNode root, int deep){
        if(root == null)return;
        if(deep > depth){
            depth = deep;
            res = root.val;
        }
        find(root.left, deep + 1);
        find(root.right, deep + 1);
    }
}

看了解析说可以迭代和递归,就都写出来了,好像没那么难?

112.路径总和

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。

这题就和前面计算到叶子节点的最大深度题目一样了,不过现在这题用递归和迭代可能差不多,在遇到叶子节点的时候判定一下就好。

递归的话需要再传入一个当前节点值,和target值。

class Solution {
   public boolean res = true;
   public boolean hasPathSum(TreeNode root, int targetSum) {
       if(root == null)return false;
       targetSum -= root.val;
       if(root.left == null && root.right == null){
           return targetSum == 0;
       }
       if(root.left != null){
           boolean left = hasPathSum(root.left,targetSum);
           if(left)return true;
       }
       if(root.right != null){
           boolean right = hasPathSum(root.right,targetSum);
           if(right)return true;
       }
       return false;
   }
}

113.路径总和||

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。

在上一题的基础上,改变输出形式即可。

class Solution {
    List<List<Integer>> result;
    LinkedList<Integer> path;
    public List<List<Integer>> pathSum (TreeNode root,int targetSum) {
        result = new LinkedList<>();
        path = new LinkedList<>();
        travesal(root, targetSum);
        return result;
    }
    private void travesal(TreeNode root,  int count) {
        if (root == null) return;
        path.offer(root.val);
        count -= root.val;
        if (root.left == null && root.right == null && count == 0) {
            result.add(new LinkedList<>(path));
        }
        travesal(root.left, count);
        travesal(root.right, count);
        path.removeLast(); // 回溯
    }
}

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

看一下一共分几步:

  • 第一步:如果数组大小为零的话,说明是空节点了。
  • 第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
  • 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
  • 第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
  • 第五步:切割后序数组,切成后序左数组和后序右数组
  • 第六步:递归处理左区间和右区间
class Solution {
    Map<Integer, Integer> map;
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        map = new HashMap<>();
        for(int i = 0; i < inorder.length; i++){
            map.put(inorder[i],i);
        }
        return findNode(inorder, 0, inorder.length, postorder, 0, postorder.length);
    }
    public TreeNode findNode(int[] inorder, int inBegin, int inEnd, int[] postorder, int postBegin, int postEnd){
        if(inBegin >= inEnd || postBegin >= postEnd)return null;
        int rootIndex = map.get(postorder[postEnd - 1]);
        TreeNode root = new TreeNode(inorder[rootIndex]);
        int lenOfLeft = rootIndex - inBegin;
        root.left = findNode(inorder, inBegin, rootIndex, postorder, postBegin, postBegin + lenOfLeft);
        root.right = findNode(inorder, rootIndex + 1, inEnd, postorder, postBegin + lenOfLeft, postEnd - 1);
        return root;
    }
}

105.从前序与中序遍历序列构造二叉树

前序遍历的第一个节点在中序遍历座位分界点

class Solution {
    Map<Integer, Integer> map;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        map = new HashMap<>();
        for (int i = 0; i < inorder.length; i++) { 
            map.put(inorder[i], i);
        }
        return findNode(preorder, 0, preorder.length, inorder,  0, inorder.length); 
    }

    public TreeNode findNode(int[] preorder, int preBegin, int preEnd, int[] inorder, int inBegin, int inEnd) {
        if (preBegin >= preEnd || inBegin >= inEnd)return null;
        int rootIndex = map.get(preorder[preBegin]);  
        TreeNode root = new TreeNode(inorder[rootIndex]);  
        int lenOfLeft = rootIndex - inBegin;  
        root.left = findNode(preorder, preBegin + 1, preBegin + lenOfLeft + 1,inorder, inBegin, rootIndex);
        root.right = findNode(preorder, preBegin + lenOfLeft + 1, preEnd,inorder, rootIndex + 1, inEnd);
        return root;
    }
}


嘿嘿