一般遇到遍历树,我们可以尝试找出规律,然后递归。
我们来看看前序遍历和中序遍历的格式:
前序:
根 | 左 | 右 |
中序:
左 | 根 | 右 |
看前序,我们可以得知,前序遍历序列的第一个元素是根,又由于题目中说,前序遍历和中序遍历结果中不含重复的数字,所以我们用前序的第一个元素可以在中序遍历中定位唯一一个根的位置,然后从中序遍历中可以划分出左子树的部分和右子树的部分。
接着,我们怎么继续递归呢,由于在中序遍历中划分出了左右子树,所以我们获取一些更多的信息以便我们后面的遍历,即可以获取左子树的区间长度和右子树的区间长度,在前序遍历里边再划分出对应的左子树的前序序列和右子树的前序序列,这样是不是就有点递归的感觉了?
代码如下所示:
class Solution {
public:
//运用哈希 来存储“根”的下标
unordered_map<int, int> index;
//这里的const是细节
TreeNode* myBuildTree(const vector<int>& preorder,const vector<int>& inorder,int preorder_left,int preorder_right,int inorder_left,int inorder_right)
{
if(preorder_left>preorder_right || inorder_left>inorder_right)
return NULL;
int preorder_index=preorder_left;
int inorder_index=index[preorder[preorder_index]];
int len=inorder_index-inorder_left;
TreeNode *root=new TreeNode(preorder[preorder_index]);
root->left=myBuildTree(preorder,inorder,preorder_left+1,preorder_left+len,inorder_left,inorder_index-1);
root->right=myBuildTree(preorder,inorder,preorder_left+len+1,preorder_right,inorder_index+1,inorder_right);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder)
{
int n=preorder.size();
for(int i=0;i<n;++i)
{
index[inorder[i]]=i;
}
return myBuildTree(preorder,inorder,0,n-1,0,n-1);
}
};
啊啊,然后还有另外一种递归的写法,就是直接创建vector的数组拷贝:
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
int n=pre.size();
int m=vin.size();
if(n==0||m==0){
return NULL;
}
TreeNode *node=new TreeNode(pre[0]);
for(int i=0;i<m;++i){
if(pre[0]==vin[i]){
vector<int> leftpre(pre.begin()+1, pre.begin()+i+1);
vector<int> leftvin(vin.begin(), vin.begin()+i);
node->left=reConstructBinaryTree(leftpre, leftvin);
vector<int> rightpre(pre.begin()+i+1, pre.end());
vector<int> rightvin(vin.begin()+i+1, vin.end());
node->right=reConstructBinaryTree(rightpre, rightvin);
break;
}
}
return node;
}
};
思路大体都是一样的,但是开销可能不一样,第一个的开销应该要小一些