题目
思路
先知道一个定律:从前序/后序遍历+中序遍历可以确定一棵不存在相同节点的二叉树
我们先复习一下深度优先的三个遍历:
- 前序遍历:根节点——左子树——右子树
- 中序遍历:左子树——根节点——右子树
- 后序遍历:左子树——右子树——根节点
所以当我们知道前序遍历和中序遍历后,大体思路如下:
- 前序遍历的第一个为根节点
- 接着我们去中序遍历中寻找根节点所在位置,那么根节点前面的就是左子树所有的节点,右边就是右子树所有的节点
- 总的来说,前序遍历就是[根节点,左子树,右子树],中序遍历就是[左子树,根节点,右子树]
代码如下:
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return Build(preorder, 0, preorder.size()-1, inorder, 0, inorder.size()-1);
}
TreeNode* Build(vector<int>&pre,int left1,int right1,vector<int>& in,int left2,int right2) {
if (left1 > right1 || left2 > right2)
return NULL;
TreeNode* root = new TreeNode(pre[left1]);//前序遍历的第一个节点为根节点
//然后在中序遍历中确定左子树和右子树的节点个数
int mid = left2;
for (int i = left2; i < in.size(); i++) {
if (in[i] == root->val) {
mid = i;
break;
}
}
//构建左子树
root->left = Build(pre, left1 + 1, left1+mid-left2, in, left2, mid-1);
root->right = Build(pre, left1 + mid - left2 + 1, right1, in, mid + 1, right2);
return root;
}
};
知道后序遍历和中序遍历后的大体思路如下:
- 后序遍历最后一个节点为根节点
- 在中序遍历中寻找根节点所在位置,根节点前面的节点就为左子树所有节点,根节点后边的节点就为右子树所有节点
- 总的来说,后序遍历就是[左子树,右子树,根节点],中序遍历就是[左子树,根节点,右子树]
代码如下:
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
return Build(inorder, 0, inorder.size() - 1, postorder, 0, postorder.size() - 1);
}
TreeNode* Build(vector<int>& in, int left1, int right1, vector<int>& post, int left2, int right2) {
if (left1 > right1 || left2 > right2)
return NULL;
TreeNode* root = new TreeNode(post[right2]);
int mid = left1;
for (int i = left1; i <= right1; i++) {
if (in[i] == root->val) {
mid = i;
break;
}
}
root->left = Build(in, left1, mid - 1, post, left2, left2 + mid - left1-1);
root->right = Build(in, mid + 1, right1, post,left2 + mid - left1, right2 - 1);
return root;
}
};
总结
重构二叉树的基本思路就是先构造根节点,再构造左子树,接下来构造右子树,其中构造左子树和右子树是一个子问题,递归处理即可。因此我们只关心如何构造根节点,以及如何递归构造左子树和右子树,再从前序,中序,后序遍历的特点来寻找根节点,左子树和右子树各自的范围