LeetCode每日一题-从前序与中序遍历序列构造二叉树

题目

给定一棵树的前序遍历 preorder 与中序遍历  inorder。请构造二叉树并返回其根节点。

Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]

Output: [3,9,20,null,null,15,7]

提示:

1 <= preorder.length <= 3000

inorder.length == preorder.length

-3000 <= preorder[i], inorder[i] <= 3000

preorder 和 inorder 均无重复元素

inorder 均出现在 preorder

preorder 保证为二叉树的前序遍历序列

inorder 保证为二叉树的中序遍历序列

 

分析

这道题最有价值的提示是preorder与inorder的元素均不重复,这对我们加速非常有帮助,否则每次确定位置时需要遍历整个数组。

解决这道问题的关键在于理解前、中、后序遍历的特点,它们都会有一个共同点:某个节点的左子树会连续地出现在数组中,右子树也会连续地出现在数组中,如下图:

从上图可以看出,三种遍历方法得到左子树都是一样长的,右子树也都一样长的,只不过它们的内部顺序不一样而已,一样的长度就成了我们的解题的关键。

前序遍历得到的数组有一个特点,就是第一个元素是根节点,包括它的左右子树都有这样的特点,这样可以通过递归来不停地处理它的子树,但如何确定左右子树的边界呢?

这个时候需要利用到中序遍历了,因为中序遍历的根节点刚好在左右子树的中间,通过这个特点可以分别算出左右子树的长度,这个长度用来帮助前序来确定左右子树的边界了。

代码

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for(int i=0;i<inorder.length;i++){
            map.put(inorder[i], i);
        }
        
        TreeNode root = new TreeNode(preorder[0]);
        recursive(0, preorder.length-1, 0, preorder.length-1, preorder, root, map);
        return root;
    }
    
    void recursive(int start, int end, int inStart, int inEnd,  int[] preorder, TreeNode parent, Map<Integer, Integer> map) {
        int treeRootIndex = map.get(preorder[start]);
        int leftTreeLen = treeRootIndex - inStart;
        if(leftTreeLen > 0){
            TreeNode leftTree = new TreeNode(preorder[start+1]);
            parent.left = leftTree;
            recursive(start+1, start+leftTreeLen, inStart, treeRootIndex-1, preorder, leftTree, map);
        }
                
        int rightTreeLen = inEnd - treeRootIndex;
        if(rightTreeLen > 0){
            TreeNode rightTree = new TreeNode(preorder[start+1+leftTreeLen]);
            parent.right = rightTree;
            recursive(start+1+leftTreeLen, end, treeRootIndex+1, inEnd, preorder, rightTree, map);
        }
    }
}

结果

​关注个人微信公众号:肌肉码农,回复“好友”讨论问题。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值