avatar

目录
105从前序与中序遍历序列构造二叉树

题目链接

题目描述:

根据一棵树的前序遍历与中序遍历构造二叉树。

太经典了,不需要例子了~

解题思路

  还是给一个例子吧!

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]

  如果这是一道选择填空甚至应用题,我们会怎么做?

  1. 由前序遍历特点可知,根结点root是”排头兵”,也就是3
  2. 根据root值找到中序遍历数组中的相应索引,这时由中序遍历特点可知,左子树位于根结点索引左侧,也就是9;右子树位于根结点索引右侧15,20,7
  3. 对左、右子树数组重复1、2步骤,直到数组为空

  这就是我们日常做题的步骤,不难发现,其中蕴含着分治和递归的思想。分治部分可以参考二分查找算法,其实没差太多~简而言之,就是利用前序遍历得到根结点值去划分中序遍历左右子树,而后按根、左、右顺序递归建立二叉树。下面说三个细节:

  1. 如何通过前序遍历的根结点值找到对应中序遍历索引?当然可以通过遍历中序数组查找到根结点值。不过,为了降低执行用时,本文采用unordered_map提前记录中序遍历键值对(亲自测试,从20ms降到12ms)。
  2. 对于划分左右子树区间以及递归结束条件的确定,参考二分查找的查找区间细节。注意本文的左右指针设置为l = 0, r = length,即[l...r)左闭右开区间。
  3. 如何确定先序遍历中根结点位置?(为什么自增就确定是下一个根结点?)一定要结合先序遍历本身特点(根结点是”排头兵”),以及我们构建二叉树的顺序(根、左、右)。这就涉及到递归的流程(考虑栈的特点),一定是等左子树建完再去建右子树。所以这样自增是么问题哒。如果是根右左建树,显然自增不管用了,得通过中序遍历数组找右子树”排头兵”,忒麻烦了~~

代码

cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public:
//分治思想,参考二分查找
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
//记录
for(int i = 0; i < inorder.size(); i++)
record.insert(make_pair(inorder[i],i)); //(结点值,结点索引)
return build(preorder, inorder, 0, inorder.size()); //[l...r)左闭右开,用于递归结束条件
}

TreeNode* build(vector<int>& preorder, vector<int>& inorder, int l, int r){
if(l == r)
return NULL;

int root_Val = preorder[root_Pre]; //从先序遍历数组中获取当前根结点值
int index = record.find(root_Val)->second; //再从中序遍历数组中找到当前根结点的索引处
root_Pre++; //为什么自增就确定是下一个根结点?
//一定要结合先序遍历本身特点(根结点是"排头兵"),以及我们构建二叉树的顺序(根、左、右)
//这就涉及到递归的流程(考虑栈的特点),一定是等左子树建完再去建右子树。
//所以这样自增是么问题哒。如果是根右左建树,显然自增不管用了,得通过中序遍历数组找右子树"排头兵",忒麻烦了。。。
TreeNode* root = new TreeNode(root_Val); //建立根结点
root->left = build(preorder, inorder, l, index); //注意是[l...r)左闭右开哦!
root->right = build(preorder, inorder, index + 1, r);

return root;
}

private:
int root_Pre = 0; //根结点在先序遍历的索引位置
unordered_map<int,int> record; //记录各结点在中序遍历数组的索引,用于通过根结点划分左右子树区域
};

如果有错误或者不严谨的地方,请务必给予指正,十分感谢。

文章作者: breadhunter
文章链接: http://yoursite.com/2020/03/08/105%E4%BB%8E%E5%89%8D%E5%BA%8F%E4%B8%8E%E4%B8%AD%E5%BA%8F%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97%E6%9E%84%E9%80%A0%E4%BA%8C%E5%8F%89%E6%A0%91/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 breadhunter
打赏
  • 微信
    微信
  • 支付寶
    支付寶