07. 重建二叉树
来源:力扣(LeetCode)
链接: https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
示例 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]
限制:
0 <= 节点个数 <= 5000
解题思路:
-
递归方法:给定前序遍历和中序遍历,前序遍历的顺序为
根→左→右
,第一个元素为根节点的值;中序遍历的顺序为左→根→右
,可以基于先序遍历的第一个元素找到根节点;基于根节点元素去中序遍历中找到根节点将其划分为左子树和右子树,分别为左右子树的中序遍历;然后基于左右子树去前序遍历中也能获得左子树的前序遍历,右子树的前序遍历;左子树与右子树都有了先序遍历和中序遍历结果,与原始问题一样,可以使用递归的方式; -
迭代方法:
- 用一个栈和一个指针辅助进行二叉树的构造。初始时栈中存放了根节点(前序遍历的第一个节点),指针指向中序遍历的第一个节点;
- 依次枚举前序遍历中除了第一个节点以外的每个节点。如果
index
恰好指向栈顶节点,那么我们不断地弹出栈顶节点并向右移动index
,并将当前节点作为最后一个弹出的节点的右儿子;如果index
和栈顶节点不同,我们将当前节点作为栈顶节点的左儿子; - 无论是哪一种情况,最后都将当前的节点入栈;
代码实现
迭代方法:
- python实现
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
d = dict()
if len(preorder) < 1:
return None
root = TreeNode(preorder[0])
for i in range(len(inorder)):
d[inorder[i]] = i
# 划分的index
index = d[root.val]
# 基于root的下标拆分
left_inorder = inorder[:index]
right_inorder = inorder[index+1:]
# 基于left_inorder的长度去找left_preorder
left_preorder = preorder[1:1+index]
right_preorder = preorder[1+index:]
root.left = self.buildTree(left_preorder, left_inorder)
root.right = self.buildTree(right_preorder, right_inorder)
return root
- c++实现
由于c++没有切片操作,因此需要构建一个函数,穿的参数包含起始与结束下标;
/**
* 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 {
private:
unordered_map<int, int> index;
public:
TreeNode* MyBuildTree(vector<int>& preorder, vector<int>& inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right)
{
if(preorder_left > preorder_right)
{
return nullptr;
}
// 前序遍历中的第一个节点就是根节点
int preorder_root = preorder_left;
// 在中序遍历中定位根节点
int inorder_root = index[preorder[preorder_root]];
// 先把根节点建立出来
TreeNode* root = new TreeNode(preorder[preorder_root]);
// 得到左子树中的节点数目
int size_left_subtree = inorder_root - inorder_left;
// 递归地构造左子树,并连接到根节点
// 先序遍历中「从 左边界+1 开始的 size_left_subtree」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
root->left = MyBuildTree(preorder, inorder, preorder_left+1, preorder_left+size_left_subtree, inorder_left, inorder_root - 1);
root->right = MyBuildTree(preorder, inorder, preorder_left+size_left_subtree+1, preorder_right, inorder_root+1, inorder_right);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int n = preorder.size();
if(n == 0)
{
return nullptr;
}
for(int i=0; i<n; i++)
{
index[inorder[i]] = i;
}
return MyBuildTree(preorder, inorder, 0, n-1, 0, n-1);
}
};
迭代方法:
- python实现
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
if not preorder:
return None
root = TreeNode(preorder[0])
stack = [root]
inorderIndex = 0
for i in range(1, len(preorder)):
preorderVal = preorder[i]
node = stack[-1]
if node.val != inorder[inorderIndex]:
node.left = TreeNode(preorderVal)
stack.append(node.left)
else:
while stack and stack[-1].val == inorder[inorderIndex]:
node = stack.pop()
inorderIndex += 1
node.right = TreeNode(preorderVal)
stack.append(node.right)
return root
- c++实现
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;
}
};
复杂度分析
- 时间复杂度: O ( N ) O(N) O(N)
- 空间复杂度: O ( N ) O(N) O(N)