Construct Binary Tree from Preorder and Inorder Traversal

https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/

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

Note:

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

Thoughts

根据二叉树的先序和中序遍历的结果还原二叉树,每个结点的值都是唯一的。由于树的递归定义,它的左子树可以通过左子树的坐标范围得到,右子树可以通过右子树坐标范围得到。前序第一个结点一定是root;而中序知道root前边肯定是左树,因此可以得到左子树的size,也就知道了pre-order中左子树坐标范围,它后面的就是右子树了。

Code

/*
 * @lc app=leetcode id=105 lang=cpp
 *
 * [105] Construct Binary Tree from Preorder and Inorder Traversal
 */

// @lc code=start
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode *dfs(vector<int> &preorder, int p_s, int p_e, vector<int> &inorder, int i_s, int i_e) {
        if (p_s > p_e) return nullptr;
        const auto root = preorder[p_s++];
        TreeNode *res = new TreeNode(root);
        int lsize = 0;
        for (int i = i_s; i <= i_e; ++i) {
            if (inorder[i] == root) {
                lsize = i - i_s;
                break;
            }
        }
        
        res->left = dfs(preorder, p_s, p_s + lsize - 1, inorder, i_s, i_s + lsize - 1);
        res->right = dfs(preorder, p_s + lsize, p_e, inorder, i_s + lsize + 1, i_e);
        return res;
    }

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        return dfs(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size() - 1);
    }
};
// @lc code=end

Analysis

Errors:

  1. 在找前序中分界点时刚开始没想到利用长度

每个元素访问一次生成一个结点,但每次访问时找mid可能需要n时间,时间复杂度O(n^2).

Ver.2

https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/discuss/34555/?page=1 假设知道pre-order的分界处在哪, 中( ..., 左末)( 右1..., 右...). 那我们可以通过一遍Pre-order traversal建树. 栈内存当前的path, 当左子树建好后, 依次把左子树结点从stack中pop, 把中右设成右1, 中抛出, 继续对右1(为右子树的root)执行此过程.

现在虽然不知道分界点, 但我们有in-order: (..., 左末, ...)中(...右...), 同样跑Pre-order, stack存path, cur为当前dfs/backtracing的树节点. 当遇到左末点时我们知道左子树已经结束, 且左末前面的点已经在建立更sub的tree时已经抛出了, 因此直接把中抛出, 如果右1存在, 进入右1. 不存在则继续顺着往上抛出, 知道遇到有右一的(in-order[j] != cur).

Last updated

Was this helpful?