面试题07. 重建二叉树

题目

给出某二叉树的前序遍历和中序遍历的结果数组,重建二叉树。假设输入的前序遍历和中序遍历中没有重复的数字。
例如:给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:[3,9,20,null,null,15,7]

与LeetCode 105 题重复:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal

算法思路

在遇到二叉树相关问题,多数都会利用递归或回溯来解题,本题也是如此。
题目分析:

  • 前序遍历的特点:【根节点 | 左子树 | 右子树】,以题目实例为例:【3 | 9 | 20 15 7】
  • 中序遍历的特点:【左子树 | 根节点 | 右子树】,以题目示例为例:【9 | 3 | 15 20 7】
  • 题目红中还给出了不包含重复的数字,表明树中每个节点都是唯一的。

所以,根据以上信息我们可以进行以下工作:

  • 1、首先前序遍历的首元素即为该树的根节点root的值,此时我们只知道根节点,而不知道根节点的左子树和右子树,需要通过后两步分析得到;
  • 2、然后在中序遍历中搜索根节点root的索引,可以将中序遍历分为【左子树 | 根节点 | 右子树】;
    -3、然后再根据中序遍历的左/右子树节点数量,将前序遍历分为【根节点 | 左子树 | 右子树】
  • 4、至此,第一层结束,继续递归前序遍历中的左/右子树,重复步骤1,依次类推。

代码:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    //pre 用于存放前序遍历的结果,作为全局变量,不用在递归时作为参数传递
    int[] pre;  
    //map用于存放中序遍历的数字及其索引,以便于通过前序的根节点找到在中序遍历中的索引
    Map<Integer,Integer> map = new HashMap<>();

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        int n = preorder.length;
        for(int i = 0;i < n;i++)  map.put(inorder[i],i);//将中序的值为键,索引为值存入map集合
        pre = preorder;
        TreeNode res = findtree(0,0,n-1);//递归调用
        return res;
    }

     /**
     * @param preroot  先序遍历的索引 当前树的根节点
     * @param left 中序遍历的索引  当前树的左边界
     * @param right 中序遍历的索引 当前树的右边界
     */
    public TreeNode findtree(int preroot,int left,int right){
        if(left > right) return null;//当left大于right时,说明当前root没有子节点
        TreeNode root = new TreeNode(pre[preroot]);  //以先序遍历的索引处的值作为根节点
        int i = map.get(pre[preroot]);//得到根节点在中序遍历中的索引
        root.left = findtree(preroot+1,left,i-1);//递归根节点的左子树,在前序遍历中,preroot = preroot+1,left不变,right为根节点的索引减1
        root.right = findtree(preroot + i -left +1,i+1,right);//递归根节点的右子树,preroot为根节点在前序遍历的索引加上左子树的长度(根节点在中序遍历的索引减去左边界left)再加1
        return root;
    }
}

复杂度
时间复杂度:O(N),前序和中序遍历都只遍历了一次
空间复杂度:O(N),引入了map

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值