今天分享的内容,也是结合leetcode中的两题,大家可以理清思路后可以去平台做一下题,检验一下成果。
首先我们还是得理解三种遍历方式的特征:
preorder: 先序遍历中,先遍历root,也就是说在先序序列中的第一个元素即原二叉树的root节点。
同理,在postorder中,由于先遍历left & right 也就是说后序序列中的最后一个元素是二叉树的root节点。
inorder的特点是: left root right,所以在其中找到root节点,我们可以直接将左子树和右子树对应的序列分开。
然后就将建原二叉树的问题转换到了左子树和右子树的构建中,依此类推,我们能可以不断将问题缩小,最后再将整合起来即可。
二叉树的描述:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
以其中一个为例,i_l,i_r分别表示中序序列的左右端点,p_l, p_r分别表示前序序列的左右端点,index表示root节点在中序序列中的下标位置。
in: [i_l, index - 1, index, index + 1, i_r]
pre: [root, p_l + 1, p_l + len, p_l + len + 1, p_r]
其中len = index - i_l == 左子树的长度。
从中序与前序遍历序列构造二叉树:
class Solution {
public:
// 递归调用 + 分治法
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.size() == 0) return NULL;
return helper(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size() - 1);
}
TreeNode* helper(vector<int> &preorder, int p_l, int p_r, vector<int> &inorder, int i_l, int i_r){
if(p_l > p_r || i_l > i_r) return NULL;
TreeNode* root = new TreeNode(preorder[p_l]);
int index = find(inorder, preorder[p_l]);//中序序列中找到根节点的位置
if(index == -1) return NULL;
int len = index - i_l; //计算出左子树的长度
root->left = helper(preorder, p_l + 1, p_l + len, inorder, i_l, index - 1);
root->right = helper(preorder, p_l + len + 1, p_r, inorder, index + 1, i_r);
return root;
}
int find(vector<int> v, int target){
if(v.size() == 0) return -1;
for(int i = 0; i < v.size(); i ++){
if(v[i] == target) return i;// 返回下标
}
return -1;
}
};
根据中序与后序遍历序列构造二叉树:
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if(inorder.size() == 0) return NULL;
return helper(inorder, 0, inorder.size() - 1, postorder, 0, postorder.size() - 1);
}
TreeNode* helper(vector<int> &inorder, int i_l, int i_r, vector<int> &postorder, int po_l, int po_r){
if(i_l > i_r || po_l > po_r) return NULL;
TreeNode* root = new TreeNode(postorder[po_r]);//取最后一个节点值
int index = find(inorder, postorder[po_r]);
if(index == -1) return NULL;
int len = index - i_l; //计算出左子树的长度
root->left = helper(inorder, i_l, index - 1, postorder, po_l, po_l + len - 1);
root->right = helper(inorder, index + 1, i_r, postorder, po_l + len, po_r - 1);
return root;
}
int find(vector<int> v, int target){
if(v.size() == 0) return -1;
for(int i = 0; i < v.size(); i ++){
if(v[i] == target) return i;// 返回下标
}
return -1;
}
};
思考:但是在这两题中,我们可以考虑将中序序列中的元素的下标和对应的数字的关系记录下来,以提高搜索速度,不用每一次都find()一次。
以上就是这篇的全部内容,有问题处烦请各位提出,谢谢!