题目
分析
知道要干啥就是写不出来……low的不行
一些函数
按想法搜索过的函数
- 在vector中查找一个元素:find()
find函数主要实现在容器内查找指定的元素,且这个元素必须是基本数据类型的
查找成功返回一个指向指定元素的迭代器,查找失败返回end迭代器
eg.在此处,后续遍历的最后一个值是根,在中序中找到这个值就可以分段
int x=postorder.back();
TreeNode node=TreeNode(x);
auto it=find(inorder.begin(),inorder.end(),x);
- find_if:带条件的查找元素
容器元素类型是类时,不能用find函数,只能通过find_if函数实现
find_if函数依次历容器的元素,返回第一个使函数为true的元素的迭代器,若查找失败则返回end迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template < typename T>
bool equal_3(T value){
return value==3;
}
int main(){
vector< int > vec;
vec.push_back(7);
vec.push_back(3);
vec.push_back(8);
vector< int >::iterator finda=find_if(vec.begin(),vec.end(),equal_3< int >);
if (finda!=vec.end())
cout<< "YES" <<*finda<<endl;
else
cout<< "ERROR" <<endl;
return 0;
}
算法
在后序周找到根节点后,找其在中序中的位置是关键,不能一直遍历吧……
所以为了高效查找根节点元素在中序遍历数组中的下标,可以创建哈希表来存储中序序列,即建立一个(元素,下标)键值对的哈希表
(根据值可以快速确定他的位置)
定义递归函数helper(in_left,in_right),表示当前递归到中序序列中当前子树的左右边界
- 若left>right,说明子树为空,返回空节点
- 选择后序遍历的最后一个节点作为根节点
- 用哈希表O(1)查询当根节点在中序遍历中下标index。从left到index-1属于左子树,index+1到right属于右子树
- 据后序遍历逻辑,递归创建右子树和左子树
NT:这里有依赖关系:先创建右子树,再创建左子树(每次选择后序遍历最后一个节点作为根节点,先构造出来的应该是右子树)
- 返回根节点root
class Solution {
int post_idx;
unordered_map<int,int> idx_map;
public:
TreeNode* help(int in_left,int in_right,vector<int> &inorder,vector<int>& postorder){
if(in_left > in_right) return nullptr;
int root_val=postorder[post_idx--]; //取后序的“最后”一个值为根节点
TreeNode* root=new TreeNode(root_val); //创建当前根节点
int position=idx_map[root_val]; //查找根节点位置
root->right = help(position+1,in_right,inorder,postorder); //切分构建左右子树
root->left=help(in_left,position-1,inorder,postorder); //注意要先创建右子树
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
post_idx = (int)postorder.size()-1; //不同执行层次取值位置不一样,所以注意这个要用全局变量,这里即类的属性
//vector的size函数返回类型是size_type,是个无符号整型
//在这不影响执行结果,不过为了最好是显式转化到int
int idx=0;
for(auto it:inorder)
idx_map[it] =idx++;
return help(0,(int)inorder.size()-1,inorder,postorder);
}
};
当时的顾虑点:
切分之后左边的根节点还得在后序中再切分在中间找……
实际过程:
因为每次都先构建的右子树,“最后位置”取值又设置的全局变量,所以一直将右遍历完后再取左边的值
这样就不需要在后序遍历中找左侧结果
像这种每次递归调用不可逆转的变量,直接设置全局变量
还有一种写法就是将inorder和postorder直接再赋值成属性,这就不需要在参数中传递了 这仅写出该赋值部分代码(毕竟C++我也有点不熟……)
class Solution{
public:
vector<int> inorder;
vector<int> postorder;
TreeNode* buildTree(vector<int>& inorder,vector<int>& postorder>{
this->inorder = inorder; //复制
this->postorder = postorder;
}
}
拓展
用中序和后序遍历恢复层序遍历
#include <bits/stdc++.h>
using namespace std;
vector<int> post,in;
map<int,int> level;
void pre(int root,int start,int end,int index)
{
if(start > end) return;
int i=start;
while(i<end && in[i]!=post[root]) i++; //在中序序列中找到根的位置
level[index] = post[root]; //在层序中标记,map默认按key的索引排序
pre(root-1-end+i,start,i-1,2*index+1); //index从0开始,所以这里左子树要+1
pre(root-1,i+1,end,2*index+2); //inde计算好每次记录的索引
}
int main()
{
int n;
cin >> n;
post.resize(n);
in.resize(n);
for(int i=0;i<n;i++) cin >> post[i];
for(int i=0;i<n;i++) cin >> in[i];
pre(n-1,0,n-1,0);
auto it = level.begin();
cout << it->second;
while(++it!=level.end()) cout << " " << it->second;
}
这里是前后计算出左、右子树结点在后序中的下标
关键找左子树下标(记住也行)