Day18~513.找树左下角的值、112. 路径总和、113.路径总和ii、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树

105 阅读3分钟

摘要

本文主要介绍了LeetCode二叉树的几个题目,包括513.找树左下角的值、112. 路径总和、113.路径总和ii、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树。

1、513.找树左下角的值

1.1 迭代法

  • 层序遍历,遍历至结束,队列ArrayDeque的第一个元素值即为最底层最左边节点的值
    public int findBottomLeftValue(TreeNode root) {
        ArrayDeque<TreeNode> deque = new ArrayDeque<>();
        deque.offer(root);
​
        int res = root.val;
        while(!deque.isEmpty()) {
            int size = deque.size();
            
            for(int i=0; i<size; i++) {
                TreeNode node = deque.poll();
                if(i == 0) {
                   res =  node.val;
                }
​
                if(node.left != null) {
                    deque.offer(node.left);
                }
                if(node.right != null) {
                    deque.offer(node.right);
                }
            }
        }
        return res;
    }

1.2 递归法

  • 递归遍历,找到所有的叶子节点,将当前叶子节点的深度与最大深度比较

  • 如果叶子节点的深度大于最大深度,设置最大深度最左节点的数值为该叶子节点的值,并更新最大深度

    • maxDept:记录最大深度
    • res:最大深度最左节点的数值
   private int maxDept;
    private int res;
​
    public int findBottomLeftValue(TreeNode root) {
        maxDept = 0;
        res = root.val;
        findLeftValue(root, 0);
        return res;
    }
​
    private void findLeftValue(TreeNode root, int dept) {
        if(root == null) {
            return;
        }
​
        if(root.left == null && root.right == null) {
            if(dept > maxDept) {
                maxDept = dept;
                res = root.val;
            }
            return;
        }
​
        findLeftValue(root.left, dept+1);
        findLeftValue(root.right, dept+1);
    }

2、112. 路径总和

2.1 思路

  • 递归+回溯
  • 递归结束:如果root为空返回false,定义newTarget=targetSum-root.val,如果节点是叶子节点(root.left == null && root.right == null)并且newTarget=0返回true
  • 递归过程:每次进入递归设置targetSum=newTarget,左右子树有一个存在就返回true

2.2 代码

    public boolean hasPathSum(TreeNode root, int targetSum) {
        if(root == null) {
            return false;
        }
​
        int newTarget = targetSum - root.val;
        if(root.left == null && root.right == null && newTarget == 0) {
            return true;
        }
        return hasPathSum(root.left, newTarget) || hasPathSum(root.right, newTarget);
    }
​

3、113.路径总和ii

3.1 思路

  • 递归+回溯
  • 判断满足条件的叶子节点的思路同112. 路径总和,如果满足条件将LinkedList加入到返回结果中
  • 递归遍历中,将当前节点的值加入到LinkedList中,遍历左右子树,遍历结束从LinkedList删除值

3.2 代码

    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>> list = new ArrayList<>();
        LinkedList<Integer> linkedList = new LinkedList<>();
        doPathSum(root, targetSum, list, linkedList);
        return list;
    }
​
    public void doPathSum(TreeNode root, int targetSum, 
        List<List<Integer>> list, LinkedList<Integer> linkedList) {
        if(root == null) {
            return;
        }
        
        linkedList.add(root.val);
​
        int newTarget = targetSum - root.val;
        if(root.left == null && root.right == null && newTarget == 0) {
            list.add(new ArrayList<>(linkedList));
        }
​
        doPathSum(root.left, newTarget, list, linkedList);
        doPathSum(root.right, newTarget, list, linkedList);
        linkedList.removeLast();
    }

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

4.1 思路

  • 首先将后序数组中的元素加入到map中,key为元素值,value为数组下标

  • 后序遍历数组最后一个元素,就是当前的中间节点

  • 找到后序数组最后一个元素在中序数组的位置,作为切割点,即通过map找到在中序数组的位置inIdx

  • 定义len为左子树的大小inIdx-inStart,因为中序数组大小一定是和后序数组的大小相同的,所以有:

    • 左子树部分:中序数组[inStart, inIdx-1],后序数组[postStart, postStart+len-1]
    • 右子树部分:中序数组[inIdx+1, inEnd],后序数组[postStart+len, postEnd-1]

4.2 代码

    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 doBuildTree(inorder, 0, inorder.length-1, postorder, 0, postorder.length-1);
    }
​
    public TreeNode doBuildTree(int[] inorder, int inStart, int inEnd, 
                int[] postorder, int postStart, int postEnd) {
        if(postStart > postEnd || inStart > inEnd) {
            return null;
        }
​
        int inIdx = map.get(postorder[postEnd]);
        int len = inIdx - inStart;  // 左子树个数
​
        TreeNode root = new TreeNode(postorder[postEnd]);
        root.left = doBuildTree(inorder, inStart, inIdx-1, postorder, postStart, postStart+len-1);
        root.right = doBuildTree(inorder, inIdx+1, inEnd, postorder, postStart+len, postEnd-1);
        return root;
    }

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

5.1 思路

  • 思路同106. 从中序与后序遍历序列构造二叉树

  • 两个关键点:

    1. 前序遍历的第一个元素在中序遍历的位置即为切割点
    2. 前序遍历和中序遍历数组大小是相同的

5.2 代码

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        for(int i=0; i<inorder.length; i++) {
            map.put(inorder[i], i);
        }
​
        // 左闭右闭
        return doBuildTree(inorder, 0, inorder.length-1, preorder, 0, preorder.length-1);
    }
​
    public TreeNode doBuildTree(int[] inorder, int inStart, int inEnd, int[] preorder, 
                int preStart, int preEnd) {
        if(inStart > inEnd || preStart > preEnd) {
            return null;
        }
​
        int idx = map.get(preorder[preStart]);
        int len = idx - inStart;
​
        TreeNode node = new TreeNode(preorder[preStart]);
        node.left = doBuildTree(inorder, inStart, idx-1, preorder, preStart+1, preStart+len);
        node.right = doBuildTree(inorder, idx+1, inEnd, preorder, preStart+len+1, preEnd);
        return node;
    }

参考资料

代码随想录-找树左下角的值

代码随想录-路径总和

代码随想录-从中序与后序遍历序列构造二叉树