以中序遍历数组和后序遍历数组为例:
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
// 第一步:判断特殊情况
if (inorder.size() == 0 || postorder.size() == 0) {
return nullptr;
}
// 第二步:确定根节点(后序数组中的最后一个节点)
int rootVal = postorder[postorder.size() - 1];
TreeNode* root = new TreeNode(rootVal);
// 如果后序数组中就一个元素,直接返回
if (postorder.size() == 1) {
return root;
}
// 第三步:以根节点的值定位切割点
//找中序数组的切割位置
int delimiterIndex;
for(delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++){
if(inorder[delimiterIndex] == rootVal){
break;
}
}
// 第四步:以切割点分割中序数组
//采用左闭右开原则
vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);//左区间:[0,delimiterIndex)
vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end());//右区间:[delimiterIndex + 1,end)
// 第五步:切割后序数组
//根据中序数组切割后的结果左右区间的大小来分割后序数组
postorder.resize(inorder.size() - 1);
// 左闭右开,注意这里使用了左中序数组大小作为切割点
vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());//[0, leftInorder.size)
vector<int> rightPostorder(postorder.begin() + leftInorder.size(),postorder.end());// [leftInorder.size(), end)
// 第六步:递归处理左区间和右区间
root->left = buildTree(leftInorder, leftPostorder);
root->right = buildTree(rightInorder, rightPostorder);
return root;
}
};
第一步:经典判断特殊情况
如果后序数组或者前序数组为空的话,直接返回nullptr就好了。
if (inorder.size() == 0 || postorder.size() == 0) {
return nullptr;
}
第二步:确定根节点
后序数组中的最后一个节点 or 前序数组的第一个节点
int rootVal = postorder[postorder.size() - 1];
//int rootVal = preorder[0];
TreeNode* root = new TreeNode(rootVal);
生成节点之后,再进行一步判断,就是后序/前序数组大小是否为1,如果是1的话就直接返回根节点就行了。
if (postorder.size() == 1) {
return root;
}
第三步:以根节点的值定位切割点
定位根节点的下标:在中序数组中遍历查询
//找中序数组的切割位置
int delimiterIndex;
for(delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++){
if(inorder[delimiterIndex] == rootVal){
break;
}
}
第四步:以切割点分割中序数组
首先需要确认切割数组的原则,本题采用的是左闭右开的原则
//采用左闭右开原则
vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);//左区间:[0,delimiterIndex)
vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end());//右区间:[delimiterIndex + 1,end)
第五步:切割后序数组
后序数组第一个元素已经用过了,需要去掉
postorder.resize(inorder.size() - 1);
如果是前序数组的话,就是去除第一个元素
preorder.erase(preorder.begin());
根据中序数组切割后的结果左右区间的大小来分割后序数组
vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());//[0, leftInorder.size)
vector<int> rightPostorder(postorder.begin() + leftInorder.size(),postorder.end());// [leftInorder.size(), end)
第六步:递归处理左区间和右区间
root->left = buildTree(leftInorder, leftPostorder);
root->right = buildTree(rightInorder, rightPostorder);
总结:通过两个数组构造二叉树只有两种方式:前序数组和中序数组,后序数组和中序数组,通过上述的解法,可以很好的解决构造二叉树的问题,本题采用递归的解法,还有迭代法的解法,有兴趣的可以进一步学习一下。