Problem: 105. 从前序与中序遍历序列构造二叉树
方法一:递归
思路
先序遍历的顺序是 [ 根节点 , [ 左子树 ] , [ 右子树 ] ] [根节点,[左子树],[右子树]] [根节点,[左子树],[右子树]]
中序遍历的顺序是 [ [ 左子树 ] , 根节点 , [ 右子树 ] ] [[左子树],根节点,[右子树]] [[左子树],根节点,[右子树]]
由于二叉树的定义具有递归性质,我们可以通过递归的方式去构造二叉树。
- 我们知道先序遍历的第一个结点是根节点,其在中序遍历的对应位置记为 i n d e x index index。通过 v a l val val去寻找值需要 O ( n ) O(n) O(n)的时间复杂度,我们可以用一个哈希表 m m m提前记录中序序列 i n o r d e r inorder inorder中 v a l val val所对应的 i n d e x index index。
- 当在中序序列中找到根节点后,被分为了三部分 [ 左子树 ] [左子树] [左子树], 根节点 根节点 根节点, [ 右子树 ] [右子树] [右子树],其中左子树和右子树可以通过递归的方式继续构造。我们知道了 左子树 左子树 左子树和 右子树 右子树 右子树中的节点数目,也就知道了子树对应的前序遍历对应的长度,因为一颗子树的前序遍历和中序遍历长度是相同的,我们将原问题拆分成了规模更小的子问题,递归解决。
- 用 [ p l , p r ] [pl, pr] [pl,pr]、 [ i l , i r ] [il, ir] [il,ir]分别表示前序遍历和中序遍历的区间范围,它们的初始值 p l = i l = 0 pl=il=0 pl=il=0, p r = i r = n − 1 pr=ir=n-1 pr=ir=n−1。当我们找到根节点后其对应左子树的中序遍历区间为: [ i l , i n e d x − 1 ] [il, inedx-1] [il,inedx−1],即左子树的长度为 i n d e x − 1 − i l index - 1 - il index−1−il,右子树的中序遍历区间为: [ i n d e x + 1 , i r ] [index + 1, ir] [index+1,ir]。
- 左子树对应的前序序列区间: [ p l + 1 , p l + 1 + i n d e x − 1 − i l ] [pl + 1, pl + 1 + index - 1 -il] [pl+1,pl+1+index−1−il], p l pl pl为根节点,左子树的根节点需要后移一位,长度为中序遍历得到的左子树长度 i n d e x − 1 − i l index -1-il index−1−il。右子树对应的前序序列区间: [ p l + i n d e x − i l + 1 , p r ] [pl+index-il + 1, pr] [pl+index−il+1,pr],去掉左子树和根的剩余部分即为右子树的区间。
- 递归边界条件:当区间不存在时没有子树,即 p l > p r pl>pr pl>pr时返回 ∅ \emptyset ∅。
Code
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int n = preorder.size();
map<int, int> m;
for(int i = 0; i < n; i++){
m[inorder[i]] = i;
}
function<TreeNode*(int, int, int, int)> dfs = [&](int pl, int pr, int il, int ir) -> TreeNode*{
if(pl > pr) return nullptr;
TreeNode* root = new TreeNode(preorder[pl]);
int index = m[root->val];
root->left = dfs(pl + 1, pl + index - il, il, index - 1);
root->right = dfs(pl + index -il + 1, pr, index + 1, ir);
return root;
};
return dfs(0, n -1, 0, n -1);
}
};
复杂度
-
时间复杂度:
O ( n ) O(n) O(n),其中n是节点的个数 -
空间复杂度:
O ( n ) O(n) O(n)