剑指 Offer 07. 重建二叉树

116 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情

题目:给定某棵二叉树的先序和中序序列,要求重建此二叉树并且返回二叉树的根节点。

例如:

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

解题思路

本题和之前 LeetCode 105.从先序和中序遍历序列构造二叉树一模一样,此处还是复习一下,根据先序序列和中序序列的组成顺序,我们可以将两个序列分为:

先序根节点左子树右子树
中序左子树根节点右子树

根据先序序列我们可以确定根节点,之后只需要确定左子树的返回和右子树的范围递归就能得到最终结果,而根据中序序列我们可以找到根节点的索引(简单的策略就是首先将中序序列存入一个map,而map中存储的是中序序列中每个元素对应的索引),根据此索引可以很容易计算出左子树和右子树的长度从而得到先序序列中左子树和右子树的起始索引和终止索引,具体分析可以看LeetCode 105.从先序和中序遍历序列构造二叉树

代码如下:

public static TreeNode buildTree(int[] preOrder, int[] inOrder){
    HashMap<Integer, Integer> map = new HashMap<>();
    for(int i=0;i<inOrder.length;i++){
        map.put(inOrder[i], i);
    }
    return buildTree(preOrder, 0, preOrder.length-1,0, inOrder.length-1, map);
}

public static TreeNode buildTree(int[] preOrder, int preLeft, int preRight, int inLeft, int inRight, HashMap<Integer, Integer> map){
    if(preLeft>preRight||inLeft>inRight) return null;
    int rootValue = preOrder[preLeft];
    TreeNode root = new TreeNode(rootValue);
    int index = map.get(rootValue);
    root.left = buildTree(preOrder, preLeft+1, index-inLeft+preLeft, inLeft, index-1, map);
    root.right = buildTree(preOrder, index-inLeft+preLeft+1, preRight, index+1, inRight, map);
    return root;
}

该算法的时间复杂度和空间复杂度都是O(n)O(n)。算法总结就是:

  1. 根据先序序列确定根节点是什么。
  2. 根据根节点将中序序列分为左子树和右子树。
  3. 递归寻找先序序列中左子树的根节点和右子树的根节点。