AcWing 1497. 树的遍历


这道题和洛谷不同的点有两个:

  1. 输入都是整数,不是连在一起的字符串。

  1. 输出是层序遍历,不是后序+中序求前序。

如果还想采用substr这种简单的做法就要先解决第一步。

定义两个string,把输入都串在一起

    for(int i=0;i<n;++i)
        cin>>t,back+=t+48;
    for(int i=0;i<n;++i)
        cin>>t,mid+=t+48;

完事之后根据根集分出左右子树集合,当然分树的前提是有子树可分。

void travel(string back_,string mid_){
    if(mid_.length()>0){//有子树可分
        char root=back_[back_.length()-1];//后序,则最后一个是根节点
        int k=mid_.find(root);//找到根节点在中序的位置,递归划分子树↓
        travel(back_.substr(0,k),mid_.substr(0,k));
        travel(back_.substr(k,mid_.size()-1-k),mid_.substr(k+1));
    }
}

因为下标是从0开始的,所以从0开始取k个,和从k位置开始取几个,这两个k的含义是有所区别的。

即下标k=5的位置实际长度是6。

画图可得左右子树划分的范围↓

再根据左右子树范围找出这些子树在根集中的范围即可

所以不管什么情况,中序的右边都是k+1开始全部取,而后序是k+1的地方开始取限定范围的根(也是画图可得)

上面那串代码就变成了递归这颗树。

譬如在下面不同位置放上cout<<root就可以实现先序遍历或者中序和后序

void travel(string back_,string mid_){
    if(mid_.length()>0){//有子树可分
        char root=back_[back_.length()-1];//后序,则最后一个是根节点
        int k=mid_.find(root);//找到根节点在中序的位置,递归划分子树↓
//cout<<root 先序遍历
        travel(back_.substr(0,k),mid_.substr(0,k));
        travel(back_.substr(k,mid_.size()-1-k),mid_.substr(k+1));
    }
}
void travel(string back_,string mid_){
    if(mid_.length()>0){//有子树可分
        char root=back_[back_.length()-1];//后序,则最后一个是根节点
        int k=mid_.find(root);//找到根节点在中序的位置,递归划分子树↓
        travel(back_.substr(0,k),mid_.substr(0,k));
//cout<<root 中序遍历
        travel(back_.substr(k,mid_.size()-1-k),mid_.substr(k+1));
    }
}

由于求的是层次遍历,所以要对代码稍作修改。

根据二叉树的结构可知,往左子树走的时候深度加1,往右子树去的时候深度先减1再加1,回来的时候再减1。

void travel(string back_,string mid_,int level){
    if(mid_.length()>0){//有子树可分
        char root=back_[back_.length()-1];//后序,则最后一个是根节点
        int k=mid_.find(root);//找到根节点在中序的位置,递归划分子树↓
        
        level++;
        travel(back_.substr(0,k),mid_.substr(0,k));
        level--;
        
        level++;
        travel(back_.substr(k,mid_.size()-1-k),mid_.substr(k+1));
        level--;
    }
}

一眼顶真发现第八行先减,第十行再加重复了,直接删掉这两行即可,再用一个vector<int>ans[level]

动态存储每一行的答案即可。

void travel(string back_,string mid_,int level){
    if(mid_.length()>0){
        char root=back_[back_.length()-1];
        int k=mid_.find(root);
        ans[level].push_back(root-48);
        level++;
        travel(back_.substr(0,k),mid_.substr(0,k),level);
        travel(back_.substr(k,mid_.size()-1-k),mid_.substr(k+1),level);
        level--;
    }
}

AC代码

#include <bits/stdc++.h>
using namespace std;
const int N=31;

string back,mid;
int n,t,tree[31];
vector<int>ans[50];
void travel(string back_,string mid_,int level){
    if(mid_.length()>0){
        char root=back_[back_.length()-1];
        int k=mid_.find(root);
        ans[level].push_back(root-48);
        level++;
        travel(back_.substr(0,k),mid_.substr(0,k),level);
        travel(back_.substr(k,mid_.size()-1-k),mid_.substr(k+1),level);
        level--;
    }
}

int main(){
    cin>>n;
    for(int i=0;i<n;++i)
        cin>>t,back+=t+48;
    for(int i=0;i<n;++i)
        cin>>t,mid+=t+48;

    travel(back,mid,1);
    for(int i=1;i<50;++i)
        for(auto j:ans[i])
            cout<<j<<" ";

    return 0;
}

按层输出所以要对二叉树的结构有清晰的认知才能做出来,比洛谷的稍微难一点。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值