目录
7-1 还原二叉树
分数 10
全屏浏览题目
切换布局
作者 DS课程组
单位 浙江大学
给定一棵二叉树的先序遍历序列和中序遍历序列,要求计算该二叉树的高度。
输入格式:
输入首先给出正整数N(≤50),为树中结点总数。下面两行先后给出先序和中序遍历序列,均是长度为N的不包含重复英文字母(区别大小写)的字符串。
输出格式:
输出为一个整数,即该二叉树的高度。
输入样例:
9
ABDFGHIEC
FDHGIBEAC
输出样例:
5
#include<stdio.h>
char pre[50];
char in[50];
int slution(int prel,int prer,int inl,int inr){
if(prel>prer)
return 0;
if(prel==prer)
return 1;
int pos=inl;
while(in[pos]!=pre[prel]){
pos++;
}
int left=slution(prel+1,prel+pos-inl,inl,pos-1)+1;
int right=slution(prel+pos-inl+1,prer,pos+1,inr)+1;
return left>right?left:right;
}
int main(){
int n;
scanf("%d",&n);
scanf("%s",pre);
getchar();
scanf("%s",in);
printf("%d",slution(0,n-1,0,n-1));
}
7-2 搜索树判断
分数 10
全屏浏览题目
切换布局
作者 DS课程组
单位 浙江大学
对于二叉搜索树,我们规定任一结点的左子树仅包含严格小于该结点的键值,而其右子树包含大于或等于该结点的键值。如果我们交换每个节点的左子树和右子树,得到的树叫做镜像二叉搜索树。
现在我们给出一个整数键值序列,请编写程序判断该序列是否为某棵二叉搜索树或某镜像二叉搜索树的前序遍历序列,如果是,则输出对应二叉树的后序遍历序列。
输入格式:
输入的第一行包含一个正整数N(≤1000),第二行包含N个整数,为给出的整数键值序列,数字间以空格分隔。
输出格式:
输出的第一行首先给出判断结果,如果输入的序列是某棵二叉搜索树或某镜像二叉搜索树的前序遍历序列,则输出YES
,否侧输出NO
。如果判断结果是YES
,下一行输出对应二叉树的后序遍历序列。数字间以空格分隔,但行尾不能有多余的空格。
输入样例1:
7
8 6 5 7 10 8 11
输出样例1:
YES
5 7 6 8 11 10 8
输入样例2:
7
8 6 8 5 10 9 11
输出样例2:
NO
#include<stdio.h>
#include<malloc.h>
typedef struct node{
int data;//键值
struct node* left;//左孩子指针
struct node* right;//右孩子指针
}Node,*NodeP;//结点
int i = 0,flag = 0;
int a[1001],b[1001];
void Preorder(NodeP root);
void Postorder(NodeP root);
NodeP Insert(NodeP root,int data);
int Judge(NodeP root,int n);
void rePreorder(NodeP root);
void rePostorder(NodeP root);
NodeP Insert(NodeP root,int data)
{
if(!root){//当为空树时,建立根节点
NodeP a = (NodeP)malloc(sizeof(Node));
a->data = data;
a->left = a->right = NULL;
root = a;
}else{//当不为空树
if(data < root->data){//新插入值小于根节点,插入至左子树
if(root->left){//当根节点左子树不为空
root->left = Insert(root->left,data);
}else{
NodeP a = (NodeP)malloc(sizeof(Node));
a->data = data;
a->left = a->right = NULL;
root->left = a;
}
}else{
if(root->right){//当根节点右子树不为空
root->right = Insert(root->right,data);
}else{
NodeP a = (NodeP)malloc(sizeof(Node));
a->data = data;
a->left = a->right = NULL;
root->right = a;
}
}
}
return root;
}
int Judge(NodeP root,int n)
{
Preorder(root);
for(int j = 0;j < n;j++){
if(a[j] != b[j]){
i = 0;
rePreorder(root);
for(int j_ = 0;j_ < n;j_++){
flag = 1;
if(a[j] != b[j])
return 1;
}
}
}
return 0;
}
void Postorder(NodeP root)
{
if(root->left)
Postorder(root->left);
if(root->right)
Postorder(root->right);
printf("%d",root->data);
if((i--)-1) printf(" ");
}
void rePostorder(NodeP root)
{
if(root->right)
rePostorder(root->right);
if(root->left)
rePostorder(root->left);
printf("%d",root->data);
if((i--)-1) printf(" ");
}
void Preorder(NodeP root)
{
a[i++] =root->data;
if(root->left)
Preorder(root->left);
if(root->right)
Preorder(root->right);
}
void rePreorder(NodeP root)//检测镜像
{
a[i++] = root->data;
if(root->right)
rePreorder(root->right);
if(root->left)
rePreorder(root->left);
}
int main()
{
int n,max;
scanf("%d",&n);//结点数
NodeP root = NULL;//初始化空树
for(int j = 0;j < n;j++){
scanf("%d",&b[j]);//输入键值
root = Insert(root,b[j]);
}
int b = Judge(root,n);
if(b)
printf("NO");
else{
if(!flag){
printf("YES\n");
Postorder(root);
}else{
printf("YES\n");
rePostorder(root);
}
}
}
7-3 完全二叉树的层序遍历
分数 10
全屏浏览题目
切换布局
作者 陈越
单位 浙江大学
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是完美二叉树。对于深度为 D 的,有 N 个结点的二叉树,若其结点对应于相同深度完美二叉树的层序遍历的前 N 个结点,这样的树就是完全二叉树。
给定一棵完全二叉树的后序遍历,请你给出这棵树的层序遍历结果。
输入格式:
输入在第一行中给出正整数 N(≤30),即树中结点个数。第二行给出后序遍历序列,为 N 个不超过 100 的正整数。同一行中所有数字都以空格分隔。
输出格式:
在一行中输出该树的层序遍历序列。所有数字都以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
8
91 71 2 34 10 15 55 18
输出样例:
18 34 55 71 2 10 15 91
#include<stdio.h>
struct tree1{
int val;
int left;
int right;
};
typedef struct tree1 tree;
tree a[100];
void bianli(int index){
if(index!=-1){
bianli(a[index].left);
bianli(a[index].right);
scanf("%d",&a[index].val);
}
}
int main(){
int N;
scanf("%d",&N);
for(int i=1;i<=N;i++){
if(i*2<=N) //左
a[i].left=2*i;
else
a[i].left=-1;
if(i*2+1<=N) //右
a[i].right=2*i+1;
else
a[i].right=-1;
}
bianli(1);
for(int i=1;i<N;i++){
printf("%d ",a[i].val);
}
printf("%d",a[N].val);
}
7-4 列出叶结点
分数 10
全屏浏览题目
切换布局
作者 陈越
单位 浙江大学
对于给定的二叉树,本题要求你按从上到下、从左到右的顺序输出其所有叶结点。
输入格式:
首先第一行给出一个正整数 N(≤10),为树中结点总数。树中的结点从 0 到 N−1 编号。随后 N 行,每行给出一个对应结点左右孩子的编号。如果某个孩子不存在,则在对应位置给出 "-"。编号间以 1 个空格分隔。
输出格式:
在一行中按规定顺序输出叶结点的编号。编号间以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
8
1 -
- -
0 -
2 7
- -
- -
5 -
4 6
输出样例:
4 1 5
#include<stdio.h>
struct node{
int left;
int right;
};
struct stack{
int front;
int end;
int arr[10];
};
typedef struct node node;
int main(){
node n[10];
int N;
scanf("%d",&N);
getchar();
char l;
char r;
int gen;
int nn[10];//用来储存每个节点的父节点
for(int i=0;i<N;i++){
scanf("%c %c",&l,&r);
getchar();
if(l!='-'){
n[i].left=l-'0';
nn[n[i].left]=1;
}
else
n[i].left=-1;
if(r!='-'){
n[i].right=r-'0';
nn[n[i].right]=1;
}
else
n[i].right=-1;
}
for(int i=0;i<N;i++){
if(nn[i]!=1){
gen=i;
break;
}
}
struct stack s;
s.end=0;
s.front=0;
s.end=s.end+1;
s.arr[s.end]=gen;
int m[10];
int k=0;
while(s.end!=s.front){
s.front=(s.front+1)%10;
if(n[s.arr[s.front]].left!=-1){
s.end=(s.end+1)%10;
s.arr[s.end]=n[s.arr[s.front]].left;
}
if(n[s.arr[s.front]].right!=-1){
s.end=(s.end+1)%10;
s.arr[s.end]=n[s.arr[s.front]].right;
}
if(n[s.arr[s.front]].right==-1&&n[s.arr[s.front]].left==-1){
m[k]=s.arr[s.front];
k++;
}
}
for(int i=0;i<k-1;i++){
printf("%d ",m[i]);
}
printf("%d",m[k-1]);
}
7-5 愿天下有情人都是失散多年的兄妹
分数 10
全屏浏览题目
切换布局
作者 陈越
单位 浙江大学
呵呵。大家都知道五服以内不得通婚,即两个人最近的共同祖先如果在五代以内(即本人、父母、祖父母、曾祖父母、高祖父母)则不可通婚。本题就请你帮助一对有情人判断一下,他们究竟是否可以成婚?
输入格式:
输入第一行给出一个正整数N
(2 ≤ N
≤104),随后N
行,每行按以下格式给出一个人的信息:
本人ID 性别 父亲ID 母亲ID
其中ID
是5位数字,每人不同;性别M
代表男性、F
代表女性。如果某人的父亲或母亲已经不可考,则相应的ID
位置上标记为-1
。
接下来给出一个正整数K
,随后K
行,每行给出一对有情人的ID
,其间以空格分隔。
注意:题目保证两个人是同辈,每人只有一个性别,并且血缘关系网中没有乱伦或隔辈成婚的情况。
输出格式:
对每一对有情人,判断他们的关系是否可以通婚:如果两人是同性,输出Never Mind
;如果是异性并且关系出了五服,输出Yes
;如果异性关系未出五服,输出No
。
输入样例:
24
00001 M 01111 -1
00002 F 02222 03333
00003 M 02222 03333
00004 F 04444 03333
00005 M 04444 05555
00006 F 04444 05555
00007 F 06666 07777
00008 M 06666 07777
00009 M 00001 00002
00010 M 00003 00006
00011 F 00005 00007
00012 F 00008 08888
00013 F 00009 00011
00014 M 00010 09999
00015 M 00010 09999
00016 M 10000 00012
00017 F -1 00012
00018 F 11000 00013
00019 F 11100 00018
00020 F 00015 11110
00021 M 11100 00020
00022 M 00016 -1
00023 M 10012 00017
00024 M 00022 10013
9
00021 00024
00019 00024
00011 00012
00022 00018
00001 00004
00013 00016
00017 00015
00019 00021
00010 00011
输出样例:
Never Mind
Yes
Never Mind
No
Yes
No
Yes
No
No
#include<stdio.h>
const int N=1e5+10;
int n,fa[N],ma[N],x,done[N],flag,t,a,b,k;
char sex[N];
void check(int x,int deep){
if(done[x]==1)
flag=0;
done[x]=1;
if(deep==5) return;
if(fa[x]!=-1) check(fa[x],deep+1);
if(ma[x]!=-1) check(ma[x],deep+1);
}
int main(){
char ch;
scanf("%d",&n);
for(int i=0;i<N;i++){
fa[i]=-1;
ma[i]=-1;
}
for(int i=0;i<n;i++){
scanf("%d",&t);
getchar();
scanf("%c",&ch);
scanf("%d %d",&a,&b);
sex[t]=ch,fa[t]=a,ma[t]=b;
if(a!=-1) sex[a]='M';
if(b!=-1) sex[b]='F';
}
scanf("%d",&k);
for(int i=0;i<k;i++){
scanf("%d %d",&a,&b);
if(sex[a]==sex[b])
printf("Never Mind\n");
else{
flag=1;
for(int j=0;j<N;j++){
done[j]=0;
}
check(a,1),check(b,1);
if(flag)
printf("Yes\n");
else
printf("No\n");
}
}
}
注意:这里使用的是c语言的写法,但是pta上的只能使用c++提交通过(我也不知道为什么)
7-6 树的遍历
分数 10
全屏浏览题目
切换布局
作者 陈越
单位 浙江大学
给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数。
输入格式:
输入第一行给出一个正整数N(≤30),是二叉树中结点的个数。第二行给出其后序遍历序列。第三行给出其中序遍历序列。数字间以空格分隔。
输出格式:
在一行中输出该树的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。
输入样例:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
输出样例:
4 1 6 3 5 7 2
#include<stdio.h>
#include<stdlib.h>
int ce[30];
int k=0;
typedef struct treenode* node;
struct treenode{
int val;
node left;
node right;
};
struct stack{
int front;
int end;
node arr[30];
};
node gettree(int a[],int b[],int sum){
//这边解释一下,传入的数组实际上是整个数组的一部分
//sum呢是你所求树的节点个数
//我们的首要任务是找到每个子树的根节点
int i;
node bt;
if(sum==0)
return NULL;
else{
bt=(node)malloc(sizeof(struct treenode));
bt->val=a[sum-1];
for(i=0;i<sum;i++){
if(b[i]==a[sum-1])
break;
}
bt->left=gettree(a,b,i);
bt->right=gettree(a+i,b+i+1,sum-i-1);
}
return bt;
}
void cengxu(node BT,int n){
if(!BT)
return;
int len=1;
int pos;
int sum=0;
node a[101],b[101];
a[0]=BT;
while(1){
if(len==0)
return;
pos=0;
for(int i=0;i<len;i++)
{
if(a[i]->left!=NULL)//如果它的左节点不为空,就存到b数组里
b[pos++]=a[i]->left;
if(a[i]->right!=NULL)//如果它的右节点不为空,就存到b数组里
b[pos++]=a[i]->right;
if(a[i]!=NULL){//不为空输出
printf("%d",a[i]->val);
sum++;
}
if(sum!=n)
printf(" ");
}
len=pos;//为下一次循环做准备
for(int i=0;i<len;i++)
a[i]=b[i];
}
}
int main(){
int n;
scanf("%d",&n);
int a[30];
int b[30];
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
for(int i=0;i<n;i++){
scanf("%d",&b[i]);
}
node BT;
BT=gettree(a,b,n);
cengxu(BT,n);
}
这边最后可以使用以上的层序遍历,也可以使用循环队列来实现可以参靠7-4代码