目录
玩转二叉树
题意:
给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜面反转,再输出反转后的层序遍历的序列。所谓镜面反转,是指将所有非叶结点的左右孩子对换。这里假设键值都是互不相等的正整数
数组代码:
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=35;
int ino[N],pre[N],tr[1<<(N/2)];
vector<int> v;
int n,num=1;
void build(int l,int r,int rt){
if(l>r){
tr[rt]=-1;
return;
}
tr[rt]=pre[num++];
//int k=int(find(ino+1,ino+n+1,tr[rt])-ino);也可以
int k=int(find(ino+l,ino+r+1,tr[rt])-ino);
build(l,k-1,rt<<1);
build(k+1,r,rt<<1|1);
}
void lev(int rt){
queue<int> q;
q.push(rt);
while(!q.empty()){
int t=q.front();q.pop();
v.push_back(tr[t]);
//注意用tr[t<<1]还是t<<1,区分开
if(~tr[t<<1|1])q.push(t<<1|1);
if(~tr[t<<1])q.push(t<<1);
}
}
int main(){
cin>>n;
ff(i,1,n)cin>>ino[i];
ff(i,1,n)cin>>pre[i];
build(1,n,1);
lev(1);
for(int i=0;i<v.size();i++){
if(i!=v.size()-1)cout<<v[i]<<" ";
else cout<<v[i]<<endl;
}
return 0;
}
结构体代码:
#include<string>
#include<queue>
#include <iostream>
#include<algorithm>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
const int maxn = 50;
struct node{
int data;
node *lchild,*rchild;
};
int n;//结点个数
int pre[maxn], in[maxn];
node* create(int preL, int preR, int inL, int inR){//建树板子
if(preL > preR) return NULL;//前序序列都没了,直接返回
node* root = new node;
root->data = pre[preL];
int k;
for(k=inL; k<=inR; k++)
if(in[k] == pre[preL])break;
int numLeft = k -inL;//左子树结点个数
// debug(numLeft);
//前序:root , [preL+1,preL + numLeft] , [preL + numLeft+1,preR]
//中序:[inL,k-1] , root , [k+1,inR]
root->lchild = create(preL+1, preL + numLeft , inL, k-1);
root->rchild = create(preL + numLeft+1, preR, k+1, inR);
return root;
}
void BFS(node* root){//层序板子
queue<node*> q;
q.push(root);
int num = 0;
while(!q.empty()){
node* now = q.front(); q.pop();
printf("%d", now->data);
if(++num < n) printf(" ");
if(now->rchild != NULL) q.push(now->rchild);
if(now->lchild != NULL) q.push(now->lchild);
}
}
int main(){
scanf("%d", &n);
for(int i=0; i<n; i++)scanf("%d",&in[i]);
for(int i=0; i<n; i++)scanf("%d",&pre[i]);
node* root = create(0, n-1, 0, n-1);
BFS(root);
return 0;
}
完全二叉树的层序遍历
思路:
建树,然后遍历即可,建树方式不唯一
代码:
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=35;
int tr[1<<(N/2)],a[N];
vector<int> v;
int n,num,p=0;
void build(int rt){
//如果这个点不在树上就返回
if(rt>n)return;
// 错误示范
// if(num<=0)return;
tr[rt]=a[num--];
build(rt<<1|1);
build(rt<<1);
}
void lev(int rt){
queue<int> q;
q.push(rt);
while(!q.empty()){
int t=q.front();q.pop();
v.push_back(tr[t]);
if(~tr[t<<1])q.push(t<<1);
if(~tr[t<<1|1])q.push(t<<1|1);
}
}
int main(){
memset(tr,-1,sizeof tr);
cin>>n;
num=n;
ff(i,1,n)cin>>a[i];
build(1);
lev(1);
for(int i=0;i<v.size();i++){
if(i!=v.size()-1)cout<<v[i]<<" ";
else cout<<v[i];
}
return 0;
}
因为是完全二叉树,层序遍历就很简单,简化版代码:
#include <iostream>
using namespace std;
int n, tr[31];
void build(int i) {
if (i > n)return;
build(2 * i);
build(2 * i + 1);
cin >> tr[i];
}
int main() {
cin >> n;
build(1);
for (int i = 1; i <= n; i++) {
if (i > 1)cout << " ";
cout << tr[i];
}
return 0;
}
Invert a Binary Tree
1102 Invert a Binary Tree (25 分)
题意:
给你二叉树的节点信息,要你建图,求其翻转(存储的时候所有左右结点都交换)后的层序和中序遍历
注意点:
字符变成数字的时候要减去'0'
if(~p[t].r)
与if(p[t].l!=-1)
是一个含义
单词解释:
- level-order:层序
- in-order:中序
- post-order:后序
- pre-order:前序
代码:
#include<bits/stdc++.h>
#define f(i,a,b) for(int i=a;i<b;i++)
#define ff(i,a,b) for(int i=a;i<=b;i++)
#define debug(x) cout<<#x<<" : "<<x<<endl;
using namespace std;
//
const int N=15;
int n,have_fa[N];
vector<int> v1,v2;
struct node{
int l,r;
}p[N];
void level_order(int rt){
queue<int> q;
q.push(rt);
while (!q.empty()){
int t=q.front();q.pop();
v1.push_back(t);
//这两种写法一个意思
if(~p[t].r)q.push(p[t].r);
if(p[t].l!=-1)q.push(p[t].l);
}
}
void in_order(int rt){
if(p[rt].r!=-1)in_order(p[rt].r);
v2.push_back(rt);
if(p[rt].l!=-1)in_order(p[rt].l);
}
int main(){
cin>>n;
f(i,0,n){
char c1,c2;
cin>>c1>>c2;
if(c1!='-'){
//作死示范
//p[i].l=c1;
p[i].l=c1-'0';
have_fa[p[i].l]=1;
}
else p[i].l=-1;
if(c2!='-'){
p[i].r=c2-'0';
have_fa[p[i].r]=1;
}
else p[i].r=-1;
}
f(i,0,n){
//找到根节点
if(!have_fa[i]){
level_order(i);
in_order(i);
break;
}
}
for(int i=0;i<v1.size();i++){
if(i!=v1.size()-1)cout<<v1[i]<<" ";
else cout<<v1[i];
}
cout<<endl;
for(int i=0;i<v2.size();i++){
if(i!=v2.size()-1)cout<<v2[i]<<" ";
else cout<<v2[i];
}
}
Tree Traversals
题意:
依次给出二叉树的后序和中序序列,构建二叉树,再对这个二叉树进行层次遍历
思路:
后序:左子树->右子树->根
中序:左子树->根->右子树
所以用后序的根分出这棵树的左右子树,再通过左子树的大小(左子树的节点个数)找到左子树的根,递归建树,之后bfs收尾
数组代码:
#include<bits/stdc++.h>
#define f(i,a,b) for(int i=a;i<b;i++)
#define ff(i,a,b) for(int i=a;i<=b;i++)
#define debug(x) cout<<#x<<" : "<<x<<endl;
using namespace std;
//
const int N=32;
//tr数组其实要开大一些,在这里数据水了
int pos[N],ino[N],tr[1<<(N/2)];
int n,point;
vector<int> v;
void build(int l,int r,int rt){
//子树为空,到叶子节点的左右节点了
if(l>r){
tr[rt]=-1;return;
}
int num=pos[point--];
tr[rt]=num;
int k=int(find(ino+l,ino+r+1,num)-ino);
//由于"post[pos--]",下面2行不能交换,要把右子树重建再重建左子树,否则会段错误
build(k+1,r,rt<<1|1);
build(l,k-1,rt<<1);
}
void lev(){
queue<int> q;
q.push(1);
while(!q.empty()){
int t=q.front();q.pop();
// 错误示范
// v.push_back(t);
v.push_back(tr[t]);
if(~tr[t<<1])q.push(t<<1);
if(~tr[t<<1|1])q.push(t<<1|1);
}
}
int main(){
cin>>n;point=n;
ff(i,1,n)cin>>pos[i];
ff(i,1,n)cin>>ino[i];
build(1,n,1);
lev();
for(int i=0;i<v.size();i++){
if(i!=v.size()-1)cout<<v[i]<<" ";
else cout<<v[i];
}
}
结构体代码:
#include<string>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 50;
struct node{
int data;
node *lchild,*rchild;
};
int n;//结点个数
int pre[maxn], in[maxn], post[maxn];
node* create(int postL, int postR, int inL, int inR){//建树板子
if(postL > postR) return NULL;//后序序列都没了,直接返回
node* root = new node;
root->data = post[postR];
int k;
for(k=inL; k<=inR; k++)
if(in[k] == post[postR])break;
int numLeft = k -inL;//左子树结点个数
//后序:[postL,postL + numLeft -1] , [postL + numLeft,postR-1] , root
//中序:[inL,k-1] , root , [k+1,inR]
root->lchild = create(postL, postL + numLeft -1, inL, k-1);
root->rchild = create(postL + numLeft, postR-1, k+1, inR);
return root;
}
void BFS(node* root){//层序板子
queue<node*> q;
q.push(root);
int num = 0;
while(!q.empty()){
node* now = q.front(); q.pop();
printf("%d", now->data);
if(++num < n) printf(" ");
if(now->lchild != NULL) q.push(now->lchild);
if(now->rchild != NULL) q.push(now->rchild);
}
}
int main(){
scanf("%d", &n);
for(int i=0; i<n; i++)scanf("%d",&post[i]);
for(int i=0; i<n; i++)scanf("%d",&in[i]);
node* root = create(0, n-1, 0, n-1);
BFS(root);
return 0;
}
当然数组也可以从1存数据:
代码(结构体):
#include<bits/stdc++.h>
#define f(i,a,b) for(int i=a;i<b;i++)
#define ff(i,a,b) for(int i=a;i<=b;i++)
#define debug(x) cout<<#x<<" : "<<x<<endl;
using namespace std;
//
const int N=35;
int post[N],ino[N],n;
vector<int> v;
struct node{
int x;
node *lc,*rc;
};
node* build(int lp,int rp,int li,int ri){
//注意返回空的特点
if(lp>rp)return nullptr;
node* root=new node;
root->x=post[rp];
int k;
for(k=li;k<=ri;k++)
if(ino[k]==post[rp])break;
int num= k - li;
root->lc=build(lp, lp + num - 1, li, k - 1);
root->rc=build(lp + num, rp - 1, k + 1, ri);
//别忘记return,否则段错误
return root;
}
void lev(node* root){
queue<node*> q;
q.push(root);
while(!q.empty()){
node* now=q.front();q.pop();
v.push_back(now->x);
if(now->lc!=nullptr)q.push(now->lc);
if(now->rc!=nullptr)q.push(now->rc);
}
}
int main(){
cin>>n;
ff(i,1,n)cin>>post[i];
ff(i,1,n)cin>>ino[i];
node* root=build(1,n,1,n);
lev(root);
for(int i=0;i<v.size();i++){
if(i!=v.size()-1)cout<<v[i]<<" ";
else cout<<v[i];
}
}
Tree Traversals Again
1086 Tree Traversals Again (25 分)
题意:
给你二叉树的前序,中序遍历,输出其后序遍历
代码(数组求解):
#include<bits/stdc++.h>
using namespace std;
const int N = 32;
const int M = 1e5;//题目不严谨,随便开的
int midt[N];
int pret[N];
int dt[M];
int pri = 1, n;
queue<int>q;
void rebuild(int l,int r,int rt){
if(l>r){
dt[rt]=-1;
return ;
}
int root=pret[pri++];//这里pri++就能做到在前序遍历中找到对应的根节点
dt[rt]=root;
int m=find(midt+l,midt+1+r,root)-midt;
//下面2行不能交换,要把左子树重建再重建右子树,否则会段错误
rebuild(l,m-1,rt<<1); //重建左子树 ,不包括中点(根节点)
rebuild(m+1,r,rt<<1|1); //重建右子树 ,不包括中点(根节点)
}
void postorder(int rt){//后序遍历正确写法
static int cnt=0;
//到叶子结点的左右节点就得停止啦
if(dt[rt]==-1)return;
postorder(rt<<1);//递归左子树
postorder(rt<<1|1);//递归右子树
if(++cnt<n)cout<<dt[rt]<<" ";
else cout<<dt[rt];
}
/*
void postorder(int rt){//后序遍历正确写法2
static int cnt=1;
if(dt[rt<<1]!=-1)postorder(rt<<1);//递归左子树
if(dt[rt<<1|1]!=-1)postorder(rt<<1|1);//递归右子树
cout<<dt[rt];
if(cnt++ < n)cout<<" ";
}
*/
/*后序遍历错误示范
void postorder(int rt){
static int cnt=0;
if(rt>n)return;
postorder(rt<<1);
postorder(rt<<1|1);
if(++cnt<n)cout<<dt[rt]<<" ";
else cout<<dt[rt];
}
*/
/*层序遍历
void bfs(){
int rt=1;
q.push(rt);
while(q.size()){
int now=q.front();
q.pop();
if(dt[now]!=-1){//到叶子结点就得停止啦
if(now!=1)cout<<" ";
cout<<dt[now];
q.push(now<<1); //先把左子树加入队列
q.push(now<<1|1); //再把右子树加入队列
}
}
}
*/
int main(){
cin>>n;
int t;string s;
stack<int> st;
int n1=0,n2=0;
for(int i=0;i<2*n;i++){
cin>>s;
if(s=="Push"){
scanf("%d",&t);st.push(t);
pret[++n1]=t;
}
else{
int k=st.top();
st.pop();
midt[++n2]=k;
}
}
rebuild(1,n,1);
postorder(1);
puts("");
return 0;
}
当然也可以全程vector模拟数组来做,代码如下(数组求解):
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=35;
int tr[1<<(N/2)];
int n,num=1;
vector<int> v1,v2,v3;
void build(int l,int r,int rt){
if(l>r){
tr[rt]=-1;
return;
}
tr[rt]=v1[num++];
//注意find函数范围
int pos=int(find(v2.begin()+0+l,v2.begin()+0+r+1,tr[rt])-v2.begin());
//题目比较水,像下面这么写也对,但不严谨
//int pos=int(find(v2.begin(),v2.end(),tr[rt])-v2.begin());
build(l,pos-1,rt<<1);
build(pos+1,r,rt<<1|1);
}
void postorder(int rt){
if(tr[rt]==-1)return;
postorder(rt<<1);
postorder(rt<<1|1);
// 错误示范
// v3.push_back(rt);
v3.push_back(tr[rt]);
}
int main(){
//默认数组从1开始,0位随便赋一个值即可
v1.push_back(-1);v2.push_back(-1);
cin>>n;
stack<int> st;
f(i,0,2*n){
string s;int t;
cin>>s;
if(s[1]=='u'){//先序
cin>>t;
v1.push_back(t);
st.push(t);
}
else{//中序
v2.push_back(st.top());
st.pop();
}
}
build(1,n,1);
postorder(1);
for(int i=0;i<v3.size();i++){
if(i!=v3.size()-1)cout<<v3[i]<<" ";
else cout<<v3[i];
}
return 0;
}
Structure of a Binary Tree
1159 Structure of a Binary Tree (30 分)
代码:
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=1e7+5,M=35;
int pos[M],ino[M],tr[N];
map<int,int> mp,dep;
int n,num;
void build(int rt,int l,int r,int d){
if(l>r){
tr[rt]=-1;return;
}
tr[rt]=pos[num--];
mp[tr[rt]]=rt;
dep[tr[rt]]=d;
int p=find(ino+l,ino+r+1,tr[rt])-ino;
build(rt<<1|1,p+1,r,d+1);
build(rt<<1,l,p-1,d+1);
}
int con(string s){
int res=0;
f(i,0,s.length()){
res=res*10+s[i]-'0';
}
return res;
}
int main(){
cin>>n;
num=n;
ff(i,1,n)cin>>pos[i];
ff(i,1,n)cin>>ino[i];
build(1,1,n,1);
int que;cin>>que;
int full=1;
ff(i,1,n){
int k=mp[pos[i]];
if((tr[k<<1]!=-1 && tr[k<<1|1]==-1)||(tr[k<<1]==-1 && tr[k<<1|1]!=-1)){
full=0;
break;
}
}
while(que--){
int res=0;
int t1,t2;
string s1,s2;
cin>>s1>>s2;
//It is a full tree
if(s1[0]=='I'){
cin>>s1>>s1>>s1;
if(full)res=1;
}
else{
t1=con(s1);
if(s2[0]=='a'){
cin>>t2>>s1>>s1;
//A and B are siblings
if(s1[0]=='s'){
if(mp[t1]/2==mp[t2]/2)res=1;
}
//A and B are on the same level
else{
cin>>s1>>s1>>s1;
if(dep[t1]==dep[t2])res=1;
}
}
else{
cin>>s1>>s1;
//A is the left child of B
if(s1[0]=='l'){
cin>>s1>>s1>>t2;
if(mp[t1]==mp[t2]*2)res=1;
}
else if(s1[0]=='r'){
//A is the root
if(s1[1]=='o'){
if(mp[t1]==1)res=1;
}
//A is the right child of B
else{
cin>>s1>>s1>>t2;
if(mp[t1]==mp[t2]*2+1)res=1;
}
}
//A is the parent of B
else{
cin>>s1>>t2;
if(mp[t1]==mp[t2]/2)res=1;
}
}
}
if(res) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}
Cartesian Tree
不知道为什么只有29分:
代码:
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int inf=2e9,N=35;
map<int,pair<int,int>> mp;
int n;
int a[N];
int build(int l,int r){
if(l>r)return -1;
int rt=N,pos;
ff(i,l,r){
if(a[i]<rt){
rt=a[i];pos=i;
}
}
mp[rt].first=build(l,pos-1);
mp[rt].second=build(pos+1,r);
return rt;
}
int main(){
cin>>n;
ff(i,1,n){
cin>>a[i];
}
build(1,n);
int rt=N;
ff(i,1,n)rt=min(rt,a[i]);
queue<int> q;
q.push(rt);
int num=0;
while(q.size()){
int t=q.front();q.pop();
cout<<t;
if(++num<n)cout<<" ";
if(~mp[t].first)q.push(mp[t].first);
if(~mp[t].second)q.push(mp[t].second);
}
return 0;
}
别人的ac代码:传送门
希望大佬给出解答😭