PAT甲级刷题计划-树
PAT甲级刷题计划-树
树整理的共25题(持续整理中,后续会补上附上树和单链表的模板hh),后续会整理相应的题号。题目参考自acwing~,争取在8.10前完成更新!
目录
- 1.数叶子结点(1004)
- 2.树的遍历(1020)
- 3.最深的根(1021)
- 4.判断二叉搜索树(1043)
- 5.完全二叉搜索树(1064)
- 6.再次树遍历(1086)
- 7.构建二叉搜索树
- 8.反转二叉树
- 9.完全二叉树
数叶子节点
家庭关系可以用家谱树来表示,给定一个家谱树,你的任务是找出其中没有孩子的成员。
输入格式
第一行包含一个整数 N表示树中结点总数以及一个整数 M表示非叶子结点数。
接下来 M行,每行的格式为:
ID K ID[1] ID[2] … ID[K]
ID是一个两位数字,表示一个非叶子结点编号,K 是一个整数,表示它的子结点数,接下来的 K 个 ID[i]也是两位数字,表示一个子结点的编号。
为了简单起见,我们将根结点固定设为 01。
所有结点的编号即为 01,02,03,…,31,32,33,…,N\ 01,02,03,…,31,32,33,…,N 01,02,03,…,31,32,33,…,N。
输出格式
输出从根结点开始,自上到下,树的每一层级分别包含多少个叶子节点。
输出占一行,整数之间用空格隔开。
数据范围
0<N<100\ 0<N<100 0<N<100
输入样例:
2 1
01 1 02
输出样例:
0 1
样例解释
该样例表示一棵只有 2个结点的树,其中 01 结点是根,而 02结点是其唯一的子节点。
因此,在根这一层级上,存在 0个叶结点;在下一个级别上,有 1个叶结点。
所以,我们应该在一行中输出0 1。
#include<iostream>
#include<cstring>
using namespace std;const int N = 110;
int h[N],idx,e[N],ne[N];
int cnt[N];void add(int a,int b)
{e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}int maxdepth = -1;void dfs(int u,int d)
{//叶子节点就是没有孩子了if(h[u]==-1) cnt[d]++;maxdepth = max(maxdepth,d);for(int i=h[u];~i;i=ne[i]){int j = e[i];dfs(j,d+1);}}int main()
{memset(h,-1,sizeof h);int n,m;cin>>n>>m;while (m -- ){int id,k;cin>>id>>k;while(k--){int son;cin>>son;add(id,son);}}dfs(1,0);cout<<cnt[0];for(int i = 1;i<=maxdepth;i++){cout<<" "<<cnt[i];}return 0;
}
2.树的遍历
一个二叉树,树中每个节点的权值互不相同。
现在给出它的后序遍历和中序遍历,请你输出它的层序遍历。
输入格式
第一行包含整数 N,表示二叉树的节点数。
第二行包含 N个整数,表示二叉树的后序遍历。
第三行包含 N个整数,表示二叉树的中序遍历。
输出格式
输出一行 N个整数,表示二叉树的层序遍历。
数据范围
1≤N≤301≤N≤301≤N≤30
官方并未给出各节点权值的取值范围,为方便起见,在本网站范围取为 1∼N。
输入样例:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
输出样例:
4 1 6 3 5 7 2
#include<iostream>
#include <unordered_map>using namespace std;const int N = 35;
int post[N],in[N];
unordered_map<int,int> l,r,pos;int build(int il,int ir,int pl,int pr)
{int root = post[pr];//根节点int k = pos[root];//根节点在中序遍历所在位置if(il<k)//还有左子树{l[root] = build(il,k-1,pl,pl+(k-1-il));}if(ir>k)//还有右子树{r[root] = build(k+1,ir,pl+k-il,pr-1); }return root;
}int q[N];void bfs(int root)
{int hh=0,tt=0;q[0] = root;while(hh<=tt) //hh指向头节点所在位置,tt指向尾节点所在位置{int t = q[hh++];//hh++是出队if(l.count(t)) q[++tt] = l[t];//++tt是入队if(r.count(t)) q[++tt] = r[t];}cout<<q[0];for(int i=1;i<=tt;i++) cout<<" "<<q[i];
}int main()
{int n;cin>>n;for (int i = 0; i < n; i ++ ) cin>>post[i];for (int i = 0; i < n; i ++ ) cin>>in[i],pos[in[i]] = i;//获取中序值的位置,方便定位根节点所在位置int root = build(0,n-1,0,n-1);bfs(root);return 0;
}
3.最深的根
一个无环连通图可以被视作一个树。
树的高度取决于所选取的根节点。
现在,你要找到可以使得树的高度最大的根节点。
它被称为最深的根。
输入格式
第一行包含整数 N,表示节点数量。
节点编号为 1∼N。
接下来 N−1
行,每行包含两个整数,表示两个节点之间存在一条边。
输出格式
输出最深的根的节点编号。
如果最深的根不唯一,则按照从小到大的顺序,将它们依次输出,每个占一行。
如果给定的图不是树,输出 Error: K components,其中 K是图中连通分量的数量。
数据范围
1≤N≤1041≤N≤1041≤N≤104
输入样例1:
5
1 2
1 3
1 4
2 5
输出样例1:
3
4
5
输入样例2:
5
1 3
1 4
2 5
3 4
输出样例2:
Error: 2 components
#include <iostream>
#include <cstring>
#include <algorithm>
#include<vector>using namespace std;
const int N = 1e4+10,M = 2*N;int p[N],h[N],e[M],idx,ne[M];void add(int a,int b)
{e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}//并查集
int find(int x)
{if(p[x]!=x) p[x] = find(p[x]);return p[x];
}//求深度
int dfs(int u,int dad)
{int depth = 0;for(int i = h[u];~i;i=ne[i]){int j = e[i];if(j==dad) continue;depth = max(depth,dfs(j,u)+1);}return depth;
}int main()
{int n;scanf("%d", &n);//初始化并查集for(int i = 1; i<= n;i++) p[i] = i;memset(h,-1,sizeof h);//初始时每个点都是一个集合int k = n;for(int i = 0; i < n-1;i++){int a,b;scanf("%d%d", &a, &b);//存双向边add(a,b),add(b,a);int pa = find(a),pb = find(b);if(pa!=pb){k--;//a的祖宗作为b的祖宗的儿子p[pa] = pb; //这句话千万不能写反了}}if(k!=1) printf("Error: %d components",k);else{vector<int> node;int maxdepth = -1;for(int i = 1;i<=n;i++){int d = dfs(i,0);if(d>maxdepth){maxdepth = d;node.clear();node.push_back(i);}else if(d==maxdepth){node.push_back(i);}}for(int i = 0;i<node.size();i++) printf("%d\n",node[i]);}return 0;
}
4.判断二叉搜索树
二叉搜索树 (BST) 递归定义为具有以下属性的二叉树:
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值
若它的右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值
它的左、右子树也分别为二叉搜索树
我们将二叉搜索树镜面翻转得到的树称为二叉搜索树的镜像。
现在,给定一个整数序列,请你判断它是否可能是某个二叉搜索树或其镜像进行前序遍历的结果。
输入格式
第一行包含整数 N,表示节点数量。
第二行包含 N个整数。
输出格式
如果给定整数序列是某个二叉搜索树或其镜像的前序遍历序列,则在第一行输出 YES,否则输出 NO。
如果你的答案是 YES,则还需要在第二行输出这棵树的后序遍历序列。
数据范围
1≤N≤10001≤N≤10001≤N≤1000
输入样例1:
7
8 6 5 7 10 8 11
输出样例1:
YES
5 7 6 8 11 10 8
输入样例2:
7
8 10 11 8 6 7 5
输出样例2:
YES
11 8 10 7 5 6 8
输入样例3:
7
8 6 8 5 10 9 11
输出样例3:
NO
#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;const int N = 1010;
//因为值可能相同,所以不使用哈希存储,而且该题貌似不需要记住树的结构,hh
int pre[N],in[N],post[N];
int cnt;
bool build(int il,int ir,int pl,int pr,int type)
{int root = pre[pl];int k = 0;if(type == 0){//到中序遍历中找到根节点,从前往后找第一个就是根节点,//因为左子树上所有结点的值均小于它的根结点的值for(k=il;k<=ir;k++)if(in[k]==root) break;//找不到这个点就说明搭建不出树if(k>ir) return false;}else{for(k=ir;k>=il;k--)if(in[k]==root) break;//找不到这个点就说明搭建不出这个树if(k<il) return false;}if(il<k)//若左子树存在{if(!build(il,k-1,pl+1,pl+1+(k-1-il),type)) return false;}if(ir>k)//若右子树存在{if(!build(k+1,ir,pl+1+(k-1-il)+1,pr,type)) return false;}//左右根,即是后序遍历post[cnt++] = root;return true;
}int main()
{int n;cin>>n;for (int i = 0; i < n; i ++ ){cin>>pre[i];in[i] = pre[i];}sort(in,in+n);if(build(0,n-1,0,n-1,0)){cout<<"YES"<<endl;cout<<post[0];for(int i = 1;i<cnt;i++ ) cout<<" "<<post[i];}else{reverse(in,in+n);cnt = 0;if(build(0,n-1,0,n-1,1)){cout<<"YES"<<endl;cout<<post[0];for(int i = 1;i<cnt;i++ ) cout<<" "<<post[i];}else cout<<"NO";}return 0;
}
5.完全二叉搜索树
二叉搜索树 (BST) 递归定义为具有以下属性的二叉树:
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值
若它的右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值
它的左、右子树也分别为二叉搜索树
完全二叉树 (CBT) 定义为除最深层外的其他层的结点数都达到最大个数,最深层的所有结点都连续集中在最左边的二叉树。
现在,给定 N个不同非负整数,表示 N 个结点的权值,用这 N个结点可以构成唯一的完全二叉搜索树。
请你输出该完全二叉搜索树的层序遍历。
输入格式
第一行包含整数 N,表示结点个数。
第二行包含 N个不同非负整数,表示每个结点的权值。
输出格式
共一行,输出给定完全二叉搜索树的层序遍历序列。
数据范围
1≤N≤10001≤N≤10001≤N≤1000 ,结点权值不超过 2000。
输入样例:
10
1 2 3 4 5 6 7 8 9 0
输出样例:
6 3 8 1 5 7 9 0 2 4
#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;const int N = 1010;int w[N],tr[N];
int n;
int cnt;//已知中序遍历void dfs(int u)
{if(u>n) return;//左dfs(2*u);tr[u] = w[cnt++];//右dfs(2*u+1);
}int main()
{memset(w,-1,sizeof w);cin>>n;for (int i = 0; i < n; i ++ ) cin>>w[i];sort(w,w+n);dfs(1);cout<<tr[1];for(int i = 2;i<=n;i++) cout<<" "<<tr[i];return 0;
}
PAT甲级刷题计划-树相关推荐
- PAT甲级刷题记录-(AcWing)-(Day06树 8题)
PAT甲级刷题记录-(AcWing)-(Day06树 8题) 课程来源AcWing 其中AcWing中的题目为翻译好的中文题目 今日刷题列表 1110 Complete Binary Tree 111 ...
- 小峰峰的pat甲级刷题记录1020
小峰峰的pat甲级刷题记录1020 方法一:通过后序和中序序列构建树,再层序输出 #include<iostream> #include<vector> using names ...
- PAT甲级刷题笔记(4)
map专题 61. 火星数字(1011) 本题要求实现火星数字和地球数字间的转换,核心任务有: (1)如何读入,N给定了读入数据个数,但是每个数据有几位数,是数字还是字母不确定: -->同一用字 ...
- 小峰峰的pat甲级刷题记录1030
很经典的最优路线问题 方法一:dfs 思路: 1.vector数组记录邻居关系用于深搜遍历 2.遍历过程中优化mindis_to[ ] ,fee[ ] 3.遍历过程中记录当前路径path 4.到达终点 ...
- PAT甲级真题目录(按题型整理)(转自柳神)
转载自:https://www.liuchuo.net/archives/2502?tdsourcetag=s_pcqq_aiomsg 最短路径 1003. Emergency (25)-PAT甲级真 ...
- BZOJ第一页刷题计划
BZOJ第一页刷题计划 已完成:67 / 90 [BZOJ1000]A+B Problem:A+B: [BZOJ1001][BeiJing2006]狼抓兔子:最小割: [BZOJ1002][FJOI2 ...
- BZOJ 2135 刷题计划(贪心,求导,二分)【BZOJ 修复工程】
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2135 是 hydro 的 BZOJ ...
- PAT甲级真题 1018 A+B in Hogwarts--python解法
PAT甲级真题 1018 A+B in Hogwarts 提交:2638 通过:1559 通过率:59% If you are a fan of Harry Potter, you would kno ...
- leetcode每日刷题计划-简单篇day8
leetcode每日刷题计划-简单篇day8 今天是纠结要不要新买手机的一天QAQ想了想还是算了吧,等自己赚钱买,加油 Num 70 爬楼梯 Climbing Stairs class Solutio ...
- leetcode刷题之树(三)
翻转二叉树,感觉做二叉树的问题好像都是那一套公式,除了个别的问题解决不了,用上篇博客leetcode刷题之树(二)的模型基本可以解决.总体来说就是树基本都可以利用递归和迭代的方法去解决,在涉及到树的遍 ...
最新文章
- 2017(秋)软工作业: (2)硬币游戏—— 代码分析与改进
- Linux中新建用户用不了sudo命令问题:rootr is not in the sudoers file.This incident will be reported解决
- MYSQL 类ORACLE序列实现遇到的问题
- php 获取用户的IP、地址、来源
- caffe安装编译教程Ubuntu16.04(CPU)教程
- SSH-keygen参数说明
- 简洁的网页跑丢了动态动画404页面源码
- 七. 多线程编程3.主线程
- 【数据结构 严蔚敏版】 顺序栈 基本操作
- 识人、识货、识场—— 这就是智能零售该有的样子
- Jboss RichFaces + Skin的简单运用示例代码
- 用css3风车转动动画代码
- pygame动画演示小球碰撞
- 史上最全的iOS面试题及答案
- 孤岛惊魂5 for Android,孤岛惊魂5手机版
- 博主制作的开源JAVA WEB游戏-《天命.罗生门》
- AJAXJS 框架用到的核心算法
- 棋牌游戏开发框架Theway 架构篇(转载)
- 活动星投票东方风云榜网络评选微信的投票方式线上免费投票
- [原创翻译]利用文字识别来查询世界