解题思路1
前序遍历的形式:
[ 根节点, [左子树的前序遍历结果], [右子树的前序遍历结果] ]
中序遍历的形式:
[ [左子树的中序遍历结果], 根节点, [右子树的中序遍历结果] ]
所以可以分治的求解该问题,难点是确定分治地边界:
- 对前序后中序分别分治,分别传入这两个遍历的左边界和右边界,直到为空结点返回NULL。
- 对每一次分治,前序遍历最左边结点的值是根结点。
- 根据上一步根结点的值,遍历中序序列,获得根结点在中序遍历的下标,获得左子树的长度,然后就可以进行下一轮分治。
代码1
/**
* 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* buildSubTree(vector<int>& preorder, vector<int>& inorder,int preLeft,int preRight,int inLeft,int inRight){
TreeNode* returnNode=new TreeNode;
if(preRight-preLeft<0)
return NULL;
for(int i = inLeft;i<=inRight;i++){
if(preorder[preLeft]==inorder[i]){
returnNode->val=inorder[i];
returnNode->left=buildSubTree(preorder,inorder,preLeft+1,preLeft+i-inLeft,inLeft,i-1);
returnNode->right=buildSubTree(preorder,inorder,preLeft+i-inLeft+1,preRight,i+1,inRight);
break;
}
}
return returnNode;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return buildSubTree(preorder,inorder,0,preorder.size()-1,0,inorder.size()-1);
}
};
解题思路2
官方更加巧妙地做法:代码中的if块是用前序数组一直构建左子树,如果碰到了inorder[inorderIndex],表示到了左下角,这时就需要往上走并处理右子树,也就是while代码块。
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (!preorder.size()) {
return nullptr;
}
TreeNode* root = new TreeNode(preorder[0]);
stack<TreeNode*> stk;
stk.push(root);
int inorderIndex = 0;
for (int i = 1; i < preorder.size(); ++i) {
int preorderVal = preorder[i];
TreeNode* node = stk.top();
if (node->val != inorder[inorderIndex]) {
node->left = new TreeNode(preorderVal);
stk.push(node->left);
}
else {
while (!stk.empty() && stk.top()->val == inorder[inorderIndex]) {
node = stk.top();
stk.pop();
++inorderIndex;
}
node->right = new TreeNode(preorderVal);
stk.push(node->right);
}
}
return root;
}
};
解法二来源:
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/solution/mian-shi-ti-07-zhong-jian-er-cha-shu-by-leetcode-s/
来源:力扣(LeetCode)