题目:
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof
解法:
1.递归
根据前序序列找到根结点,再根据中序序列找到包括此根结点的全部结点,不断重复此过程递归找到所有结点。
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
};
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.size()<=0||inorder.size()<=0||preorder.size()!=inorder.size()) return NULL;
int h1=0,t1=preorder.size()-1,h2=0,t2=inorder.size()-1; //先序、序的前后。
return bt(preorder,inorder,h1,t1,h2,t2);
}
TreeNode* bt(vector<int>& preorder, vector<int>& inorder,int h1,int t1,int h2,int t2)
{
//h1,t1是前序的root的子节点们;h2,t2是中序的root的子节点们
TreeNode *root = new TreeNode;
int i,leftL,rightL;
//找根结点
root->val = preorder[h1];
//分开左右子树
for(i = h2; i < t2; i++ )
{
if(inorder[i]==root->val)break;
}
leftL = i-h2;
rightL = t2-i;
if(leftL>0)
{
//左子树存在 找左子树的所有结点构成书
root->left = bt(preorder,inorder,h1+1,t1-rightL,h2,t2-rightL-1);
}else root->left = NULL;
if(rightL>0)
{
//右子树存在 找右子树的所有结点构成书
root->right = bt(preorder,inorder,h1+leftL+1,t1,h2+leftL+1,t2);
}else root->right = NULL;
return root;
}
/*
迭代版,效率高
在先序遍历中,前后紧邻的两个节点a和b,在树中的位置有三种情况
1、b是a的左子树节点(父子关系),对应a有左子树
2、b是a的右子树节点(父子关系),对应a没有左子树,但有右子树
3、b是a的某个有右子树的祖父节点,对应a既没有左子树,也没有右子树
因为在前序遍历中,a的祖父节点和祖父节点的左子树绝不可能在a的后面,
在中序遍历中,前后紧邻的两个节点a和b,在树中的位置有两种情况:
1、b是a的右子树中的最左侧节点,对应a有右子树(在a右子树只有一个节点的情况下,退化为b是a的右节点)
2、a是b的左子树中的最右侧节点,对应a没有右子树(在b的左子树只有一个节点的情况下,退化为a是b的左节点)
作者:adsk47
链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/solution/cliang-chong-jie-fa-di-gui-die-dai-by-ad-wx6w/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/
//时间最快的解法
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.empty()) return nullptr;
stack<TreeNode*> s;
TreeNode *root=new TreeNode(preorder[0]); //根节点
TreeNode *cur=root; //正在确定位置的节点
for(int i=1,j=0;i<preorder.size();i++) {
//有左子树的情况,一直沿左子树深入,并将沿途节点放入栈中
if (cur->val != inorder[j]) { //inorder[j]代表最左节点(去除已经确定左子树的节点)
cur->left = new TreeNode(preorder[i]);
s.emplace(cur);
cur = cur->left;
} else { //没有左子树的情况
j++;
while (!s.empty() && s.top()->val == inorder[j]) { //栈顶是其父节点,判断有无右子树
cur = s.top(); //没有右子树,就追溯到有右节点的祖父节点
s.pop();
j++;
}
cur = cur->right = new TreeNode(preorder[i]); //preorder[i]即当前节点的右子树节点,并且下次从右子树开始遍历
}
}
return root;
}
};