Construct Binary Tree from Preorder and Inorder Traversal

update Aug 29, 2017 23:07

LeetCodearrow-up-right

Given preorder and inorder traversal of a tree, construct the binary tree.

Note: You may assume that duplicates do not exist in the tree.

Basic Idea:

通过观察,我们可以发现 preorder 遍历的结果的第一个数一定是 root,而在 inorder list 中,root 会把左右两子树一分为二,利用这种性质,我们可以得到一种递归解法:

  • 对于输入inorder lst 和 preorder lst,先标记 preorde[0] 作为 root,然后在 inorder 中查找 root 的位置;

  • 这样就将两个 list 分为了两部分,分表为当前root左右子树的元素,对左右子树递归执行;

例如,对于input:

preorder: [1,2,4,5,7,3,6]
inorder:  [4,2,7,5,1,3,6]

我们可以看到,对于以 1 为 root 的树,我们可以用 1 将 inorder 分成两部分,递归传给下层函数的参数分别为:

left:                        right:
    preorder: [2,3,5,7]            preorder: [3,6]
    inorder   [4,2,7,5]            inorder:  [3,6]

Java Code:

    class Solution {
        public TreeNode buildTree(int[] preorder, int[] inorder) {
            return helper(preorder, inorder);
        }
        private TreeNode helper(int[] preorder, int[] inorder) {
            if (preorder.length == 0 ) return null;
            if (preorder.length == 1) return new TreeNode(preorder[0]);
            TreeNode root = new TreeNode(preorder[0]);
            int root_idx = indexOf(inorder, preorder[0]);
            int l_subtree_size = root_idx;
            int r_subtree_size = inorder.length - root_idx - 1;
            if (l_subtree_size > 0) {
                root.left = helper(Arrays.copyOfRange(preorder, 1, l_subtree_size + 1), Arrays.copyOfRange(inorder, 0, root_idx));
            }
            if (r_subtree_size > 0) {
                root.right = helper(Arrays.copyOfRange(preorder, l_subtree_size + 1, preorder.length),
                                    Arrays.copyOfRange(inorder, root_idx + 1, inorder.length));
            }
            return root;
        }
        private int indexOf(int[] arr, int target) {
            for (int i = 0; i < arr.length; ++i) {
                if (arr[i] == target) return i;
            }
            return -1;
        }
    }

Python Code:

update Dec 24, 2017 3:01

Update:

时间复杂度: 因为我们每次在inorder list中找root位置时候都要线性搜索,时间复杂度为 O(n^2),可以预处理一下,用一个 map 存放所有 node 在 inorder list 中的 index,这样时间复杂度变为 O(n),但空间复杂度从 O(1) 变为 O(n);

更新一个优化了时间复杂度的 Java 实现:

update 2018-06-06 22:41:13

Update C++ Solution

运用之前的思路,用C++写了一个解法:

update 2021-06-08

时隔三年的再一次更新,希望这次也会有好结果。

可以注意到,事实上没有必要维持每次递归时候preorder数组的右边界,因为我们每次都只需要取preorder中的第一个作为这次的root,所以只需要传入每次preorder的起点。

Last updated