问题描述
给定一棵树的前序遍历 preorder
与中序遍历 inorder
。请构造二叉树并返回其根节点。
示例 1:
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
示例 2:
Input: preorder = [-1], inorder = [-1]
Output: [-1]
提示:
1 <= preorder.length <= 3000
inorder.length == preorder.length
-3000 <= preorder[i], inorder[i] <= 3000
preorder
和inorder
均无重复元素inorder
均出现在preorder
preorder
保证为二叉树的前序遍历序列inorder
保证为二叉树的中序遍历序列
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
法I:递归
//从前序遍历和中序遍历序列构造二叉树
//递归
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (preorder.size() == 0) {
return nullptr;
}
TreeNode* root = new TreeNode(preorder[0]);
int leftSize = 0;
for (int i = 0; i < inorder.size(); i++) {
if (inorder[i] == preorder[0]) {
leftSize = i;//确定左子树的长度
break;
}
}
auto preLeftBegin = preorder.begin() + 1;
auto preLeftEnd = preorder.begin() + leftSize + 1;
auto preRightBegin = preorder.begin() + leftSize + 1;
auto preRightEnd = preorder.begin() + preorder.size();
auto inLeftBegin = inorder.begin();
auto inLeftEnd = inorder.begin() + leftSize;
auto inRightBegin = inorder.begin() + leftSize + 1;
auto inRightEnd = inorder.begin() + inorder.size();
vector<int> preLeft(preLeftBegin, preLeftEnd);
vector<int> inLeft(inLeftBegin, inLeftEnd);
vector<int> preRight(preRightBegin, preRightEnd);
vector<int> inRight(inRightBegin, inRightEnd);
TreeNode* leftTree = buildTree(preLeft, inLeft);
TreeNode* rightTree = buildTree(preRight, inRight);
root->left = leftTree;
root->right = rightTree;
return root;
}
};
看看执行结果:
分析:
递归函数的设计思路在于,我们输入前序遍历序列和中序遍历序列,能输出该序列对应的根结点。前序序列的第一个值为根结点,把改值在中序序列中找到,便能确定左子的总长度,因此也能确定右子长度。我们分别确定左右子在前序和中序序列中的位置,便能确定左右子分别的前序序列和中序序列,调用递归函数,获取左右子结点。
法II:迭代
太难了,先粘一下官方代码吧:
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (!preorder.size()) {
return nullptr;
}
TreeNode* root = new TreeNode(preorder[0]);
stack<TreeNode*> stk;//先序入栈
stk.push(root);
int inorderIndex = 0;
for (int i = 1; i < preorder.size(); ++i) {//以先序的方式创建一棵二叉树
int preorderVal = preorder[i];
TreeNode* node = stk.top();
if (node->val != inorder[inorderIndex]) {//还没有到最左子
node->left = new TreeNode(preorderVal);
stk.push(node->left);
}
else {//到达最左子
while (!stk.empty() && stk.top()->val == inorder[inorderIndex]) {//判断是否有右子,若没有右子
node = stk.top();
stk.pop();
++inorderIndex;
}
//有右子
node->right = new TreeNode(preorderVal);
stk.push(node->right);
}
}
return root;
}
};