1 什么是重建二叉树
直接看力扣题
105. 从前序与中序遍历序列构造二叉树
106 从中序与后序遍历序列构造二叉树
综上所述,重建二叉树其实就是根据前+中或中+后这两种遍历后的结果将我们原来的二叉树形式恢复出来。
我们复习一下二叉树的几种遍历
有二叉树如下所示
前序:根 —》 左 —》 右 的顺序打印
ABDHKECFIGJ
中序:左 —》 根 —》 右 的顺序打印
HKDBEAIFCGJ
后序:左 —》 右 —》 根 的顺序打印
KHDEBIFJGCA
2 分析-以前序+中序为例
假设我们知道了前序数组preOrder为
ABDHKECFIGJ
中序数组inOrder为
HKDBEAIFCGJ
0、假设辅助函数rebuild能够重建二叉树
TreeNode* rebuild(vector<int>& preOrder/*前序数组*/,int preBegin/*前序开始*/, int preEnd/*前序结束*/, vector<int>& inOrder/*中序数组*/, int inBegin/*中序开始*/, int inEnd/*中序结束*/);
注1:使用递归的basecase:preBegin > preEnd就返回nullptr
注2:下面操作全在辅助函数内进行
1、我们能够通过前序数组第一个值new一个根结点
TreeNode* root = new TreeNode(preOrder[0]);
2、前序告诉我们根结点的val为A,我们可以找到中序中A的索引
3、此时在中序数组中inRootPos左侧为树的左子树,右侧为右子树,同样可以把前序数组preOrder分为左右两部分
4、对左子树部分重建二叉树
root->left = rebuild(前序数组,前序开始, 前序结束, 中序数组, 中序开始, 中序结束);
int leftSize = inRootPos- inBegin;
root->left = rebuild(preOrder, preBeagin + 1, leftSize + preBeagin, inOrder, inBegin, inRootPos- 1); 此处范围看上图3
重建后结果如下所示(下一次的重建范围)
5、对右子树部分重建二叉树
root->right = rebuild(前序数组,前序开始, 前序结束, 中序数组, 中序开始, 中序结束);
root->right = rebuild(preOrder, leftSize + preBeagin + 1, preEnd, inOrder, inRootPos + 1, inEnd); 看图3
重建后结果如下所示(下一次的重建范围)
3 框架以及注意部分
代码框架-适用于前+中 中+后:
修改部分
前+中 :
//1、我们能够通过前序数组第一个值new一个根结点
int RootVal = preOrder[preBeagin];
int leftSize = inRootPos- inBegin;
// 4对左子树重建
root->left = rebuild(preOrder, preBeagin + 1, leftSize + preBeagin, inOrder, inBegin, inRootPos- 1);
// 5对右子树重建
root->right = rebuild(preOrder, leftSize + preBeagin + 1, preEnd, inOrder, inRootPos + 1, inEnd);
代码实现:
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return build(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size() - 1);
}
//辅助函数
TreeNode* rebuild(vector<int>& preOrder, int preBeagin, int preEnd, vector<int>& inOrder, int inBegin, int inEnd)
{
//base case
if (preBeagin > preEnd)
{
return nullptr;
}
//1、我们能够通过前序数组第一个值new一个根结点
int RootVal = preOrder[preBeagin];
TreeNode* root= new TreeNode(RootVal);
//2、找到中序遍历的根的位置
int inRootPos = -1;
for (int i = inBegin; i <= inEnd; i++)
{
if(inorder[i] == RootVal)
{
inCur = i;
break;
}
}
int leftSize = inRootPos- inBegin;
// 4对左子树重建
NewHead->left = rebuild(preOrder, preBeagin + 1, leftSize + preBeagin, inOrder, inBegin, inRootPos- 1);
// 5对右子树重建
NewHead->right = rebuild(preOrder, leftSize + preBeagin + 1, preEnd, inOrder, inRootPos + 1, inEnd);
return NewHead;
}
};
中+后:
修改部分:
//1、寻找根结点
int rootVal = postOrder[posEnd];
//对子节点进行递归
int leftSize = inPos - inBegin;
// 4
root->left = rebuild(inOrder, inBegin, inPos - 1, postOrder, posBegin, leftSize + posBegin - 1);
//区间很重要,一定要画图理解!!
// 5
root->right = rebuild(inOrder, inPos + 1, inEnd, postOrder, leftSize + posBegin, posEnd - 1);
代码实现:
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
return build(inorder, 0, inorder.size() - 1, postorder, 0, postorder.size() - 1);
}
TreeNode* rebuild(vector<int>& inOrder, int inBegin, int inEnd, vector<int>& postOrder, int posBegin, int posEnd)
{
//base case
if (posBegin > posEnd)
{
return nullptr;
}
//1、寻找根结点
int rootVal = postOrder[posEnd];
TreeNode* root = new TreeNode(rootVal);
//找到在中序数组的根的索引
int inPos = -1;
for (int j = inBegin; j <= inEnd; j++)
{
if (rootVal == inOrder[j])
{
inPos = j;
break;
}
}
//对子节点进行递归
int leftSize = inPos - inBegin;
// 4
root->left = rebuild(inOrder, inBegin, inPos - 1, postOrder, posBegin, leftSize + posBegin - 1);
//区间很重要,一定要画图理解!!
// 5
root->right = rebuild(inOrder, inPos + 1, inEnd, postOrder, leftSize + posBegin, posEnd - 1);
return root;
}
};