题目描述
思路
根据前序历遍和中序历遍确定树。这里的思路是明确的。因为前序历遍,开头第一个元素就是树的根节点。在中序历遍中,确定了对应的根节点的位置,中序历遍中,根节点左边的全部元素构成树的左子树的节点,根节点右边的全部元素构成树的右子树的所有节点。
具体做法:
- 在先序前序历遍序列中找到树的根节点。
- 在中序历遍后找到树的树的根节点位置。
- 在前序历遍中,左子树的根节点为父节点之后的一个元素。由中序历遍中根节点的位置,可以知道左子树有多少个节点,由此可以在前序历遍中计算得到右子树的根节点的位置。
- 递归的调用就可以得到树。
解答
/**
* 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* buildTree(vector<int>& preorder, vector<int>& inorder) {
return fun(preorder,inorder,0,inorder.size()-1,0);
}
/*其中
inorder_start是中序历遍序列的左端点
i是中序历遍中根节点的位置
inorder_end是中序历遍的序列的右端点
*/
TreeNode* fun(vector<int>& preorder,vector<int>& inorder, int inorder_start, int inorder_end, int pre_root_index)
{
if(inorder_start==inorder_end) return new TreeNode(preorder[pre_root_index]);
if(inorder_start>inorder_end) return NULL;
int root_value=preorder[pre_root_index];
TreeNode* root=new TreeNode(root_value);
int i=0;
for(;i<inorder.size();++i)
{
if(inorder[i]==root_value)
break;
}
root->left=fun(preorder, inorder, inorder_start, i-1, pre_root_index+1);
root->right=fun(preorder, inorder, i+1, inorder_end, pre_root_index+i-inorder_start+1);
return root;
}
};
总结:
其实这道题并不好理解,很容易出错,涉及好多边界条件的考虑。网上有一篇写得很好的博客,虽然他的方法并不好,涉及大量的内容占用。每次递归都需要生成新的数组序列用于递归。但是他的这种做法有一个好处就是容易让人理解这个题的思路。博客地址。