输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
限制:
0 <= 节点个数 <= 5000
先序序列中依次出现的数字是根,在先序中找根,在中序中找到根的位置,根的位置左边是左子树,右边是右子树,划分出中序序列的左右子树。假设中序序列的左子树有n个结点,那么在先序的根中向后数n个数字,即为先序序列的左子树,后面的为先序序列的右子树,因此可划分出先序序列的左子树和先序序列的右子树。这样,先序的左子树和中序的左子树又重新构成一组先序遍历和中序遍历序列,右子树同理。因此可递归的找下去。
/**
* 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:
map<int, int> mp;
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
for(int i = 0;i < inorder.size();i++)
mp[inorder[i]] = i;
return Bulid(preorder, 0, preorder.size()-1, inorder, 0, inorder.size()-1);
}
TreeNode* Bulid(vector<int>& preorder, int pre_left, int pre_right, vector<int>& inorder, int in_left, int in_right){
if(pre_left > pre_right || in_left > in_right)
return NULL;
int mid = mp[preorder[pre_left]];//找到先序根在中序序列的位置,用哈希可以节省时间,也可以不用map,每次从头到尾遍历中序,找出根
TreeNode* root = new TreeNode(preorder[pre_left]);
int num = mid - in_left;
root->left = Bulid(preorder, pre_left+1, pre_left+num, inorder, in_left, mid-1);
root->right = Bulid(preorder, pre_left+num+1, pre_right, inorder, mid+1, in_right);
return root;
}
};
有关先序左子树的边界、先序右子树的边界、中序左子树的边界、中序右子树的边界划分,如下图所示:
关于递归边界的问题:
递归到叶子结点时候结束递归,此时结点的左右两边结点数为0,即num=0,则有pre_left+1 > pre_left,即pre_left > pre_right。
或者有mid = in_right,则有mid+1 > in_right,即in_left > in_right。