二叉树前序遍历的顺序为:
先遍历根节点;
随后递归地遍历左子树;
最后递归地遍历右子树。
二叉树中序遍历的顺序为:
先递归地遍历左子树;
随后遍历根节点;
最后递归地遍历右子树。
在「递归」地遍历某个子树的过程中,我们也是将这颗子树看成一颗全新的树,按照上述的顺序进行遍历。挖掘「前序遍历」和「中序遍历」的性质,我们就可以得出本题的做法。
案例讲解:
https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/submissions/
算法思路:
我们用一个栈和一个指针辅助进行二叉树的构造。初始时栈中存放了根节点(前序遍历的第一个节点),指针指向中序遍历的第一个节点;
我们依次枚举前序遍历中除了第一个节点以外的每个节点。如果 index 恰好指向栈顶节点,那么我们不断地弹出栈顶节点并向右移动 index,并将当前节点作为最后一个弹出的节点的右儿子;如果 index 和栈顶节点不同,我们将当前节点作为栈顶节点的左儿子;
无论是哪一种情况,我们最后都将当前的节点入栈。
/**
* 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* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(!preorder.size()){
return nullptr;
}
stack<TreeNode*>stk;
TreeNode* root = new TreeNode(preorder[0]);//前序遍历的第一个元素就是二叉树的根
stk.push(root);//把根节点放入栈中
int inorderIndex=0;//指针指向中序遍历的第一个节点,inorderIndex是第一个节点
for(int i=1;i<preorder.size();i++)//枚举前序遍历中除了第一个节点以外的每个节点
{
int preorderVal=preorder[i];
TreeNode*node=stk.top();
if(node->val != inorder[inorderIndex]){//如果 index 和栈顶节点不同
node->left=new TreeNode(preorderVal);//将当前节点作为栈顶节点的左儿子
stk.push(node->left);
}else
//如果 index 恰好指向栈顶节点(无左子树),那么我们不断地弹出栈顶节点并向右移动 index,并将当前节点作为最后一个弹出的节点的右儿子;
{
while(!stk.empty()&&stk.top()->val==inorder[inorderIndex])
{
node=stk.top();
stk.pop();//弹出栈顶节点
++inorderIndex;//向右移动 index
}
node->right=new TreeNode(preorderVal);//将当前节点作为最后一个弹出的节点的右儿子
stk.push(node->right);
}
}
return root;
}
};
c++:
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
if(pre.size() == 0){
return nullptr;
}
int root_val = pre[0];
int root_index_vin;
TreeNode* root = new TreeNode(pre[0]);
for(int i = 0; i < vin.size(); i++){
if(vin[i] == root_val){
root_index_vin = i;
break;
}
}
vector<int>p_l(pre.begin()+1, pre.begin()+root_index_vin+1);//2,4,7
vector<int>v_l(vin.begin(), vin.begin()+root_index_vin);//4,7,2
vector<int>p_r(pre.begin()+root_index_vin+1, pre.end());//3,5,6,8
vector<int>v_r(vin.begin()+root_index_vin+1, vin.end());//5,3,8,6
root->left = reConstructBinaryTree(p_l, v_l);
root->right = reConstructBinaryTree(p_r, v_r);
return root;
}
};
python:
class Solution:
# 返回构造的TreeNode根节点
def reConstructBinaryTree(self, pre, tin):
# write code here
if not pre:
return None
# 根节点
root = TreeNode(pre[0])
# 根节点在中序遍历中的位置索引
tmp = tin.index(pre[0])
# 递归 构造树的左子树
root.left = self.reConstructBinaryTree(pre[1:tmp+1], tin[:tmp])
# 递归构造树的右子树
root.right = self.reConstructBinaryTree(pre[tmp+1:], tin[tmp+1:])
return root