输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
递归解析:
递推参数: 前序遍历中根节点的索引pre_root、中序遍历左边界in_left、中序遍历右边界in_right。
终止条件: 当 in_left > in_right ,子树中序遍历为空,说明已经越过叶子节点,此时返回 nullnull 。
递推工作:
建立根节点root: 值为前序遍历中索引为pre_root的节点值。
搜索根节点root在中序遍历的索引i: 为了提升搜索效率,本题解使用哈希表 dic 预存储中序遍历的值与索引的映射关系,每次搜索的时间复杂度为 O(1)O(1)。
构建根节点root的左子树和右子树: 通过调用 recur() 方法开启下一层递归。
左子树: 根节点索引为 pre_root + 1 ,中序遍历的左右边界分别为 in_left 和 i - 1。
右子树: 根节点索引为 i - in_left + pre_root + 1(即:根节点索引 + 左子树长度 + 1),中序遍历的左右边界分别为 i + 1 和 in_right。
返回值: 返回 root,含义是当前递归层级建立的根节点 root 为上一递归层级的根节点的左或右子节点。
时间/空间 O(n)
class Solution {
public:
unordered_map<int,int> map;
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
// 将中序序列用哈希表存储,便于查找根节点
for(int i = 0;i < inorder.size();i++)
map[inorder[i]] = i;
// 传入参数:前序,中序,前序序列根节点,中序序列左边界,中序序列右边界
return build(preorder,inorder,0,0,inorder.size()-1);
}
TreeNode* build(vector<int>& preorder, vector<int>& inorder,int pre_root,int in_left,int in_right){
if(in_left > in_right)
return NULL;
TreeNode* root = new TreeNode(preorder[pre_root]);
// 根节点在中序序列中的位置,用于划分左右子树的边界
int in_root = map[preorder[pre_root]];
// 左子树在前序中的根节点位于:pre_root+1,左子树在中序中的边界:[in_left,in_root-1]
root->left = build(preorder,inorder,pre_root+1,in_left,in_root-1);
// 右子树在前序中的根节点位于:根节点+左子树长度+1 = pre_root+in_root-in_left+1
// 右子树在中序中的边界:[in_root+1,in_right]
root->right = build(preorder,inorder,pre_root+in_root-in_left+1,in_root+1,in_right);
return root;
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
self.dic, self.po = {}, preorder
for i in range(len(inorder)):
self.dic[inorder[i]] = i
return self.recur(0, 0, len(inorder) - 1)
def recur(self, pre_root, in_left, in_right):
if in_left > in_right:
return # 终止条件:中序遍历为空
root = TreeNode(self.po[pre_root]) # 建立当前子树的根节点
i = self.dic[self.po[pre_root]] # 搜索根节点在中序遍历中的索引,从而可对根节点、左子树、右子树完成划分。
root.left = self.recur(pre_root + 1, in_left, i - 1) # 开启左子树的下层递归
root.right = self.recur(i - in_left + pre_root + 1, i + 1, in_right) # 开启右子树的下层递归
return root # 返回根节点,作为上层递归的左(右)子节点