题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
思路
给定先序序列和中序序列,在不考虑递归的情况下,根据先序和中序的遍历顺序我们可以将其分别划分:
- 先序序列:[根节点 | 左子树 | 右子树];
- 中序序列:[左子树 | 根节点 | 右子树];
本题的核心思想是:
- 由先序序列确定根节点;
- 在中序序列中找到此根节点(无重复元素)
- 中序序列根节点左侧节点数量(元素数量)即为左子树上元素数量;右子树同理;
- 由先序遍历性质可知,在左子树存在的情况下,先序序列中根节点索引 + 1即为左子树根节点的索引;在右子树的存在的情况下,根节点索引 + (左子树长度 + 1)即为右子树根节点索引。
- 根据3、4获得左子树的根节点索引与左子树对应序列的范围 和 右子树的根节点索引与右子树对应序列的范围;
- 递归。
C++代码
class Solution {
public:
unordered_map<int, int> dic;//创建哈希表存储中序序列中元素对应的下标
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int len = inorder.size();
for(int i = 0; i < len; i ++ ){
dic[inorder[i]] = i;//存储
}
//先序序列的根节点一定从0开始
return Pre_In_build(0, 0, len - 1, preorder);
}
TreeNode* Pre_In_build(int root, int left, int right, vector<int>& preorder){
//root是先序序列中的索引,left、right是中序序列的索引
if(left > right)return NULL;//若left==right当前节点是叶子结点,若left>right返回空值
int idx = dic[preorder[root]];//取出根节点root在中序序列中的下标
TreeNode* node = new TreeNode(preorder[root]);//新建节点
//递归,idx将原中序序列一分为二,在其左侧的是左子树,右侧的是右子树
node->left = Pre_In_build(root + 1, left, idx - 1, preorder);
//左子树在先序序列上对应的根节点是root + 1,在中序序列上对应的区间是[left, idx - 1]
node->right = Pre_In_build(root + 1 + idx - left, idx + 1, right, preorder);
//右子树在先序序列上对应的根节点是root + 1 + idx - left;在中序序列上对应的区间是[idx + 1, right]
return node;
}
};
本文正在参与「掘金 3 月闯关活动」,点击查看活动详情。