105. 从前序与中序遍历序列构造二叉树
返回与给定的前序和后序遍历匹配的任何二叉树。
pre 和 post 遍历中的值是不同的正整数。
思路
刷到了这道题,然后想着把这类题目都总结下,这类问题的关键是从根节点的位置区别左右子树,前序遍历的preinorder[pre_start]必定是第一个根节点,然后在中序遍历中找到该节点的位置index,这样inorder[in_start, index - 1]就是左子树了,inorder[index + 1, in_end]就是右子树,找出了左右子树的范围后就可以确定左右子树的节点的数量了,再反过来定位preorder的位置即可。
- 左子树值数量:left_size = index - in_start,preorder递归范围[pre_start + 1, pre_start + left_size],inorder递归范围[ib, index - 1]
- 右子树值数量:right_size = in_end - index(其实不用算),直接根据上面得出的范围即可,preorder递归范围[pre_start + left_size + 1, pre_end],inorder递归范围[index + 1, in_end]
代码
/**
* 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 {
public:
unordered_map<int, int> root_idx;
TreeNode* dfs(vector<int>& preorder, int pb, int pe, vector<int>& inorder, int ib, int ie) {
if(pb > pe) {
return nullptr;
}
//取出根节点值
int val = preorder[pb];
//在中序遍历中找到根节点位置
int index = root_idx[val];
//建树
TreeNode* root = new TreeNode(val);
//计算左子树值数量
int left_size = index - ib;
//递归确定左右子树
root -> left = dfs(preorder, pb + 1, pb + left_size, inorder, ib, index - 1);
root -> right = dfs(preorder, pb + left_size + 1, pe, inorder, index + 1, ie);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int n = preorder.size();
int idx = 0;
for(const int& num : inorder) {
root_idx[num] = idx++;
}
return dfs(preorder, 0, n - 1, inorder, 0, n - 1);
}
};
106. 从中序与后序遍历序列构造二叉树
根据一棵树的中序遍历与后序遍历构造二叉树。
思路
同理,后序遍历的最后一个postorder[post_end]必定是根节点,然后根据该值在中序遍历中寻找根节点位置,分为左右子树即可。需要注意的是,直接从后序倒序遍历时,会先访问到右子树的根节点,所以先构建右子树。
/**
* 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 {
public:
int post_idx;
unordered_map<int, int> root_idx;
TreeNode* dfs(int start, int end, vector<int>& inorder, vector<int>& postorder) {
if(start > end) {
return nullptr;
}
int index = root_idx[postorder[post_idx]];
post_idx--;
TreeNode* root = new TreeNode(inorder[index]);
root -> right = dfs(index + 1, end, inorder, postorder);
root -> left = dfs(start, index - 1, inorder, postorder);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
post_idx = postorder.size() - 1;
int idx = 0;
for(const int& num : inorder) {
root_idx[num] = idx++;
}
return dfs(0, inorder.size() - 1, inorder, postorder);
}
};
889. 根据前序和后序遍历构造二叉树
返回与给定的前序和后序遍历匹配的任何二叉树。
pre 和 post 遍历中的值是不同的正整数。
思路
可以知道preorder[pre_start + 1]必定为左子树的根节点,然后再postordered中找出该位置即可。
代码
/**
* 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 {
public:
unordered_map<int, int> post_idx;
TreeNode* dfs(vector<int>& pre, vector<int>& post, int pre_b, int pre_e, int post_b, int post_e) {
if(pre_b > pre_e) {
return nullptr;
}
TreeNode* root = new TreeNode(pre[pre_b]);
//只有一个节点了,直接返回
if(pre_b == pre_e) {
return root;
}
//找到左子树的根节点
int val = pre[pre_b + 1];
//在后序遍历定位
int index = post_idx[val];
//计算左子树数量
int left_size = index - post_b + 1;
//递归左右子树
root -> left = dfs(pre, post, pre_b + 1, pre_b + left_size, post_b, index);
root -> right = dfs(pre, post, pre_b + left_size + 1, pre_e, index + 1, post_e - 1);
return root;
}
TreeNode* constructFromPrePost(vector<int>& pre, vector<int>& post) {
int n = post.size();
for(int i = 0; i < n; i++) {
post_idx[post[i]] = i;
}
return dfs(pre, post, 0, n -1, 0, n -1);
}
};