[LC] 从中序与后序遍历序列构造二叉树

题目

题目描述

分析

知道要干啥就是写不出来……low的不行

一些函数

按想法搜索过的函数

  1. 在vector中查找一个元素:find()
    find函数主要实现在容器内查找指定的元素,且这个元素必须是基本数据类型的
    查找成功返回一个指向指定元素的迭代器,查找失败返回end迭代器
    eg.在此处,后续遍历的最后一个值是根,在中序中找到这个值就可以分段
int x=postorder.back();
TreeNode node=TreeNode(x);
auto it=find(inorder.begin(),inorder.end(),x);
  1. 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;

}

这里是前后计算出左、右子树结点在后序中的下标
关键找左子树下标(记住也行)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值