这个题比较难理解,建议在草稿纸上自己演示一遍程序的执行过程,执行的样例可以按照这个例子
思路就会慢慢清晰。
规则:先根遍历:根左右。中根遍历:左根右
题目给的两个数组,先根遍历和中跟遍历,先根遍历的第一个元素就是根节点,在中根遍历中,根节点把中根遍历数组分为两部分,分别是左子树和右子树,那么左右子树又可以根据这个性质,再继续划分。整体思路就是这样。
比较难理解的地方就是,如何求出左右子树在中根遍历数组中的起始位置和终止位置。也就是代码中的recur函数的参数,
node->left = recur(root + 1, left, idx_inor[preorder[root]] - 1);
node->right = recur(root + 1 + idx_inor[preorder[root]] - left,idx_inor[preorder[root]] + 1 , right);
recur函数有3个形参,它们都是数组的下标,第一个参数是根节点在先根数组中的下标,第二个和第三个参数是左右边界在中根数组中的下标。详细的代码含义注意看代码中写的注释
/**
* 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:
vector<int> preorder, inorder;
unordered_map<int, int> idx_inor;
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
this->preorder = preorder;
this->inorder = inorder;
int len = preorder.size();
for (int i = 0; i < len; i ++) {
idx_inor[inorder[i]] = i;//中序遍历用hash表存储,可以根据节点的值得到节点在中序数组中的下标
}
return recur(0, 0, len - 1);
}
TreeNode* recur(int root, int left, int right) {//三个形参都表示下标,root是根节点在preorder的下标,left和right是左右边界在inorder的下标
if (left > right) return NULL;
TreeNode* node = new TreeNode(preorder[root]);
int i = idx_inor[preorder[root]];//记录根节点在中根数组中的下标
node->left = recur(root + 1, left, i - 1);//上一根节点在先根数组的下标是root,那么根据规则,左子树的根节点下标就是root + 1,左子树的起点就是中根数组的left,终点就是上一根节点的下标i - 1(左根右)
node->right = recur(root + 1 + i - left, i + 1 , right);//上一根节点在先根数组的下标是root,那么根据规则(根左右,左根右),右子树的根节点就是root + 左子树的节点数 + 1,就是 root + (左子树的右边界 - 左子树的左边界 + 1) + 1,即 root + (i - 1 - left + 1) + 1 = root + i -left + 1,右子树的左边界在中序数组的下标就是i + 1,右边界就是right。
return node;
}
};