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

根据一棵树的中序遍历与后序遍历构造二叉树。

注意: 你可以假设树中没有重复的元素。

例如,给出

中序遍历 inorder = [9,3,15,20,7] 后序遍历 postorder = [9,15,7,20,3] 返回如下的二叉树:

3

/
9 20 / \

15 7

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解:

如何根据两种遍历序列构造数: 中序,和前序 / 后序等等

  • 通常从前序遍历或者后序遍历开始,根据不同遍历方法的规律,选择合适的节点构造树
    • 比如,前序遍历的第一个节点就是根节点,然后是它的左子节点,右子节点。
    • 后序遍历的最后一个节点是根节点,然后是它的右子节点,左子节点。
  • 从先序 / 后序序列中找到根节点,根据根节点将中序序列分为左子树,右子树。 从中序序列中获得的信息是: 如果当前子树为空 (返回 None), 否则继续构造子树。
算法步骤:
  1. 创建map用来存放中序遍历的值和下标。
  2. rootIdx 用来存放后序遍历数组中,创建root节点的下标
  3. 将后序遍历数组全局化
  4. 后序遍历的最后一个元素是根节点,先拿到根节点,在上述map中查找在中序遍历中的index, 因为中序遍历顺序为 左 中 右。 所以左子树为[0, index - 1], 右子树为[index + 1, end]。
  5. 递归构造根节点的 右子树 和 左子树。 这里要注意,一定是先构造右子树。 因为后序遍历的顺序为 左 右 中 ,所以出去最后一个元素后,最后一个元素为右子树的根节点
  6. 依次构建,直到没有元素。

代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// map中存放中序遍历的节点和索引值
    HashMap<Integer,Integer> map = new HashMap<>();
    int[] postorder = null;
    int rootIdx = 0;

    public TreeNode buildTree(int[] inorder, int[] postorder) {

        if (inorder.length == 0 || postorder.length == 0 || inorder.length != postorder.length) return null;
        if (inorder.length == 1) return new TreeNode(inorder[0]);

        this.postorder = postorder;
        this.rootIdx = postorder.length - 1;
        // 将中序遍历的节点和索引值存入数组
        for (int i = 0; i < inorder.length; i++) {
            map.put(inorder[i],i);
        }

        return buildTreeHelper(0,inorder.length - 1);
    }


    private TreeNode buildTreeHelper(int is, int ie){

        // 左边索引 > 右边索引 -> 没有元素
        if (is > ie) return null;

        // 后序遍历最后一位是根节点,或者根节点的索引
        int idx = map.get(postorder[rootIdx]);

        // 根节点
        TreeNode node = new TreeNode(postorder[rootIdx]);

        rootIdx --;
        // 右子树 :  【idx + 1, inorder.length - 1】
        node.right = buildTreeHelper(idx + 1, ie);
        // 左子树 :  【0 , idx-1】
        node.left = buildTreeHelper(is,idx - 1);

        return node;
    }
复杂度分析:

时间复杂度: O(N), 递归N次,其中N为节点个数

空间复杂度:O(N), 使用递归,需要额外的栈空间,由于栈的深度为N,故空间复杂度为 O(N).