leetcode 105.从前序与中序遍历序列构造二叉树
题目链接:leetcode 105
1.题目
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
2.示例
1)示例 1:
输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]
2)示例 2:
输入: preorder = [-1], inorder = [-1]
输出: [-1]
3.数据范围
1 <= preorder.length <= 3000
inorder.length == preorder.length
-3000 <= preorder[i], inorder[i] <= 3000
preorder 和 inorder 均 无重复 元素
inorder 均出现在 preorder
preorder 保证 为二叉树的前序遍历序列
inorder 保证 为二叉树的中序遍历序列
4.分析
首先明确树的两种遍历,其中先序遍历指的是先遍历根节点,然后遍历左子树,最后遍历右子树,中序遍历指的是先遍历左子树,然后遍历根节点,最后遍历右子树。那么对于一个确定的preorder[x]为根节点的情况下,那么左子树的所有节点必须满足:preorder[y]且preorder[y]在inorder中的位置小于preorder[x]在inorder中的位置,当x+1也满足这个条件时,那么preorder[x+1]即为它的左儿子节点。并且满足上述条件的最大y值为Y,则preorder[Y+1]即为它的右儿子节点(这里需要注意的是,每次根节点需要更新左儿子的范围,也就是必须要小于右儿子开始点)
5.代码
class Solution {
public:
map<int,int> mp1,mp2,mp3;
void get_range_left(int pos,int right,vector<int>& preorder){
int k=mp1[pos];
while(k+1<=right) {
if(mp2[preorder[k+1]]<=mp2[pos])
k++;
else
break;
}mp3[pos]=k;
if(mp1[pos]+1<=right) get_range_left(preorder[mp1[pos]+1],k,preorder);
if(k+1<preorder.size()) get_range_left(preorder[k+1],right,preorder);
}
void build1(TreeNode* head,int R,vector<int>& preorder, vector<int>& inorder){
int pos=mp3[head->val],pos1=mp1[head->val];
if(pos1+1<=min(pos,R)){
TreeNode *left=new TreeNode(preorder[pos1+1]);head->left=left;
build1(left,pos,preorder,inorder);
}
if(pos+1<=R){
TreeNode *right=new TreeNode(preorder[pos+1]);head->right=right;
build1(right,R,preorder,inorder);
}
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
for(int i=0;i<preorder.size();i++){
mp1[preorder[i]]=i;
mp2[inorder[i]]=i;
}
get_range_left(preorder[0],preorder.size()-1,preorder);
// TreeNode *root=new TreeNode(mp3[2]);
TreeNode *root=new TreeNode(preorder[0]);
build1(root,preorder.size()-1,preorder,inorder);
return root;
}
};