根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3 / \ 9 20 / \ 15 7
解题思路:
需要掌握的基础知识:前序遍历,中序遍历,递归,双指针,哈希。
根据先序遍历的特点,数组的首个元素data必然是根结点,中序遍历的特点是根结点后于左子树访问,于是如果我们能找到data在inorder中出现的位置pos(哈希),那么就能得到pos之前的所有元素(个数num1)为左子树所有元素的中序遍历,pos之后的所有元素(个数num2)则是右子树的中序遍历。根据先序遍历的特点,首个元素必然是根结点,之后的num1个是左子树的先序遍历,再之后的num2个数则是右子树的先序遍历。经过这一波分析,可以看出,大的问题拆解成了两个小问题,而这些小问题不会重复计算,很显然只序递归就能解决。再递归的过程中,这些小的数组没有必要开辟额外的空间,利用双指针,确定在大的数组中的访问范围即可,这样一来就基本完美了。
class Solution { public: TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { int size_pre = preorder.size(), size_in = inorder.size(); if (size_pre == 0 || size_in == 0) return NULL; pre = preorder; in = inorder; for (int i = 1; i <= size_in; i++) { mp[inorder[i - 1]] = i - 1; } TreeNode* root = build(0, size_pre, 0, size_in); return root; } TreeNode* build(int pre_first, int pre_last, int in_first, int in_last) { if (pre_last == pre_first || in_first == in_last) return NULL; if (pre_last - pre_first == 1) return new TreeNode(pre[pre_first]); int pos = mp[pre[pre_first]]; TreeNode* root = new TreeNode(pre[pre_first]); root->left = build(pre_first + 1, pre_first + 1 + pos - in_first, in_first, pos); root->right = build(pre_first + 1 + pos - in_first, pre_last, pos + 1, in_last); return root; } private: vector<int> pre, in; unordered_map<int, int> mp; }; |