PAT (Advanced Level) Practice 1153 Decode Registration Card of PAT 字符串处理综合

一、概述

给出若干考生的考生号,每位意义不同。找出满足条件的考生。

字符串处理问题。

我的解题思路还是有很大缺陷的。

一开始我就确定了思路:利用sscanf分解考生号,使用结构体储存每一位考生的信息。

然后遇到了第一个问题,sscanf不会用。

调函数调了半天,调好了。

然后开始处理三种询问。

注意这里,要有一个中心思想,就是仅处理“合法的”,用字符串的角度处理。否则会犯和我一样的错误,只能得十五分。哭出来。

“合法的”指的是什么呢?指的是在题目中要求的范围,具体来说就是:

询问类型只考虑123,对于1,只考虑bat,对于二,只考虑数字,对于3,也只考虑数字。

用字符串的角度处理指的又是什么呢?指的是不要把输入看成数字,全看成字符串,不然debug有的受,具体来说就是:

比如说2,我们需要输入考场号,一看有效范围100-999,就用%d输入int吧。错了,不行。为什么不行?因为输入可能是字符,就是abc什么的。这就是边界条件。

而scanf用%d时有一个特点,遍历缓冲区,可以认为是打回车前的输入,找到第一个数字,逮出来赋值。

那么如果我缓冲区没有数字怎么办?scanf遍历一遍,没找着,过去了。但是它也不敢清空缓冲区啊,没那个胆子也没那个权限。

那么我们看查询如果输入 2 B会出现什么情况:

首先%d输入2,发现是二号询问,问考场考生的,然后%d输入考场号,由于2被拿走了,剩个B,这个scanf找不着数字,就跳过,报NA,不清缓冲区。下一次又是输入2,又发现是二号询问,无限循环。。。

发现了什么?就是需要根据输入响应输出时候,如果题中没给限制(比如说图论中,所有节点编号为1-N,或者所有输入均为非负不同整数),那么就不能耿直的按正确的输入,要按字符串输入。谁知道神经病使用者会输入什么玩意儿进来。

二、分析

(一)字符串数组风格

对于这种分割字符串题目,如果要用sscanf,注意三点:

1、sscanf的第一个参数是一个大字符串

2、sscanf的第三个参数,如果不是字符串,要加&

3、sscanf的第二个参数,可以加数量限制,比如说我要一个字符,就可以%1s

因此输入处理如下:

struct student
{
	char level[10];
	char set[10];
	char date[10];
	char num[10];
	int score;
	char ID[20];
	string realID;
}S[10010];
int N,M;
scanf("%d %d",&N,&M);
for(int i=0;i<N;i++)
{
	scanf("%s %d",S[i].ID,&S[i].score);
	sscanf(S[i].ID,"%1s%3s%6s%3s",S[i].level,S[i].set,S[i].date,S[i].num);
	S[i].realID=S[i].ID;
}

为什么我要有一个realID呢,因为用string可以直接在cmp里比较,这样方便。

sort没法对两个字符串数组比较大小,必须转为string,char数组转string还是很简单的,直接等于号赋值即可。

score要用int保存,不能用字符串数组,因为用字符串数组的话,99就跑到100前面去了,因为9比1大。

所以还是很麻烦的。

然后处理询问。如下:

for(int i=1;i<=M;i++)
	{
		char q;
		cin>>q;
		if(q=='1')
		{
			char x[10];
			cin>>x;
			cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
			vector<student> v; 
			if(!strcmp(x,"B")||!strcmp(x,"A")||!strcmp(x,"T"))
			{
				for(int j=0;j<N;j++)
				{
					if(!strcmp(S[j].level,x))
					v.push_back(S[j]);
				}	
				if(v.size()==0)
				printf("NA\n");
				else
				{
					sort(v.begin(),v.end(),cmp);
					for(int k=0;k<v.size();k++)
					printf("%s %d\n",v[k].ID,v[k].score);
				}
			}
			else
			printf("NA\n");
		}
		else if(q=='2')
		{
			char x[10];
			cin>>x;
			cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
			int num=0;
			int sum=0;
			for(int j=0;j<N;j++)
			{
				if(!strcmp(S[j].set,x))
				{
					num++;
					sum+=S[j].score;
				}
			}
			if(num>0)
			printf("%d %d\n",num,sum);
			else
			printf("NA\n");
		}
		else if(q=='3')
		{
			char x[10];
			cin>>x;
			cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
			unordered_map<int,int> m;
			for(int j=0;j<N;j++)
			{
				if(!strcmp(S[j].date,x))
				{
					m[atoi(S[j].set)]++;
				}
			}
			if(m.size()==0)
			printf("NA\n");
			else
			{
				vector<node> v;
				unordered_map<int,int>::iterator it;
				for(it=m.begin();it!=m.end();it++)
				{
					node leaf;
					leaf.set=it->first;
					leaf.num=it->second;
					v.push_back(leaf);
				}
				sort(v.begin(),v.end(),cmp1);
				vector<node>::iterator iter;
				for(iter=v.begin();iter!=v.end();iter++)
				{
					printf("%d %d\n",iter->set,iter->num);
				}
			}
		}
		else
		{
			string x;
			cin>>x;
			//scanf("%s",x);
			cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
			cout<<"NA\n";
			//printf("Case %d: %s %s\nNA\n",i,q,x);
		}
	}

首先注意一点,询问的两个参数,都用字符串数组存储。

然后判断。容易出错的有以下几个地方:

询问1,要先选出对应级别的人,再排序。而不能最开始全排序好。那样顺序有问题。如果输入不是BAT,要输出NA,如果输入的是BAT但是人数为0,也要输出NA。如果最开始选择vector存储,然后排序,判断人数,就简单一些。

询问2,应该是最简单的了。选择对应考场的然后累加即可。

询问3,最麻烦。因为要注意两个参数,考场和人数,先按人数再按考场排。要选出对应日期的人,存在哪里呢?可以存在map里。map如果第二个参数是int,那么不赋值时就是0,很方便。但是我们注意map是有序的,这就意味着对其进行插入操作会花时间,而且map这个有序的特性我们也用不着。于是可以使用undered_map。这个单纯是个hash表,没有排序特性,我们利用哈希特性就好了。在unordered_map中存完之后,用一个结构体vector再转存一遍。然后对vector再排序输出即可。

注意如果出现询问567abc,那也要返回NA。

这样就可以了。

(二)string风格

我们可以看出,使用字符串数组还是有点麻烦的,主要麻烦在排序、判断相等、还占空间。如果能直接在考生号里面进行比较就好了。这时,我们要拿出subctr函数。

substr是string的一个函数,参数有两个,a,b,用于返回从a开始长度为b的子串。用这个就可以实现我们要的功能了。

首先结构体和输入就简单得多。

struct student
{
	string ID;
	int score;
}s[100100];
for(int i=0;i<N;i++)
{
	cin>>s[i].ID;
	cin>>s[i].score;
}

看上去十分赏心悦目啊。

然后是处理询问。注意能不用switch就不用switch。使用strsub之后比较相等简直简单了很多。具体的逻辑实现还是没什么区别的。如下:

for(int i=1;i<=M;i++)
	{
		string q,x;
		cin>>q;
		cin>>x;
		cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
		if(q=="1")
		{
			vector<student> v;
			for(int j=0;j<N;j++)
			{
				if(s[j].ID.substr(0,1)==x)
				{
					v.push_back(s[j]);
				}
			}
			sort(v.begin(),v.end(),cmp);
			if(v.size()!=0)
			{
				for(int k=0;k<v.size();k++)
				{
					cout<<v[k].ID<<" "<<v[k].score<<"\n";
				}
			}
			else
			cout<<"NA\n";
		}
		else if(q=="2")
		{
			int num=0,sum=0;
			for(int j=0;j<N;j++)
			{
				if(s[j].ID.substr(1,3)==x)
				{
					num++;
					sum+=s[j].score;
				}
			}
			if(num!=0)
			printf("%d %d\n",num,sum);
			else
			cout<<"NA\n";
		}
		else if(q=="3")
		{
			unordered_map<string,int> m;
			for(int j=0;j<N;j++)
			{
				if(s[j].ID.substr(4,6)==x)
				{
					m[s[j].ID.substr(1,3)]++;
				}
			}
			if(m.size()==0)
			cout<<"NA\n";
			else
			{
				unordered_map<string,int>::iterator it;
				vector<node> v;
				for(it=m.begin();it!=m.end();it++)
				{
					node leaf;
					leaf.num=it->second;
					leaf.set=it->first;
					v.push_back(leaf);
				}
				sort(v.begin(),v.end(),cmp1);
				for(int j=0;j<v.size();j++)
				{
					cout<<v[j].set<<" "<<v[j].num<<"\n";
				}
			}
		}
		else
		{
			cout<<"NA\n";
		}
	}

三、总结

字符串处理,substr是利器,用于只要求比较相等而不需要具体找出来再处理。如果需要找出来然后处理的话也可以用sscanf和sprintf。

string还有一个函数也很好用,就是fing,成功时返回首位位置,失败时返回string::npos,就是失败这个比较难记。

PS:代码如下:

字符串版:

#include<stdio.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<iostream>
#include<math.h>
#include<algorithm>
#include<unordered_map>
using namespace std;
struct student
{
	char level[10];
	char set[10];
	char date[10];
	char num[10];
	int score;
	char ID[20];
	string realID;
}S[10010];
struct node
{
	int set;
	int num=0;
};
bool cmp(student a,student b)
{
	if(a.score!=b.score)
	return a.score>b.score;
	else
	return a.realID<b.realID;
  /*if(a.level!=b.level)
  return a.level<b.level;
  else
  return a.score>b.score;*/
}
bool cmp1(node a,node b)
{
	if(a.num!=b.num)
	return a.num>b.num;
	else
	return a.set<b.set;
}
int main()
{
	int N,M;
	scanf("%d %d",&N,&M);
	for(int i=0;i<N;i++)
	{
		scanf("%s %d",S[i].ID,&S[i].score);
		sscanf(S[i].ID,"%1s%3s%6s%3s",S[i].level,S[i].set,S[i].date,S[i].num);
		S[i].realID=S[i].ID;
	}
	//sort(S,S+N,cmp);不应该在这里排序 
	for(int i=1;i<=M;i++)
	{
		char q;
		cin>>q;
		if(q=='1')
		{
			char x[10];
			cin>>x;
			cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
			vector<student> v; 
			if(!strcmp(x,"B")||!strcmp(x,"A")||!strcmp(x,"T"))
			{
				for(int j=0;j<N;j++)
				{
					if(!strcmp(S[j].level,x))
					v.push_back(S[j]);
				}	
				if(v.size()==0)
				printf("NA\n");
				else
				{
					sort(v.begin(),v.end(),cmp);
					for(int k=0;k<v.size();k++)
					printf("%s %d\n",v[k].ID,v[k].score);
				}
			}
			else
			printf("NA\n");
		}
		else if(q=='2')
		{
			char x[10];
			cin>>x;
			cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
			int num=0;
			int sum=0;
			for(int j=0;j<N;j++)
			{
				if(!strcmp(S[j].set,x))
				{
					num++;
					sum+=S[j].score;
				}
			}
			if(num>0)
			printf("%d %d\n",num,sum);
			else
			printf("NA\n");
		}
		else if(q=='3')
		{
			char x[10];
			cin>>x;
			cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
			unordered_map<int,int> m;
			for(int j=0;j<N;j++)
			{
				if(!strcmp(S[j].date,x))
				{
					m[atoi(S[j].set)]++;
				}
			}
			if(m.size()==0)
			printf("NA\n");
			else
			{
				vector<node> v;
				unordered_map<int,int>::iterator it;
				for(it=m.begin();it!=m.end();it++)
				{
					node leaf;
					leaf.set=it->first;
					leaf.num=it->second;
					v.push_back(leaf);
				}
				sort(v.begin(),v.end(),cmp1);
				vector<node>::iterator iter;
				for(iter=v.begin();iter!=v.end();iter++)
				{
					printf("%d %d\n",iter->set,iter->num);
				}
			}
		}
		else
		{
			string x;
			cin>>x;
			//scanf("%s",x);
			cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
			cout<<"NA\n";
			//printf("Case %d: %s %s\nNA\n",i,q,x);
		}
	}
}

string版:

#include<stdio.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<iostream>
#include<math.h>
#include<algorithm>
#include<unordered_map>
using namespace std;
struct student
{
	string ID;
	int score;
}s[100100];
struct node
{
	string set;
	int num;
};
bool cmp(student a,student b)
{
	if(a.score!=b.score)
	return a.score>b.score;
	else
	return a.ID<b.ID;
}
bool cmp1(node a,node b)
{
	if(a.num!=b.num)
	return a.num>b.num;
	else
	return a.set<b.set;
}
int main()
{
	int N,M;
	scanf("%d %d",&N,&M);
	for(int i=0;i<N;i++)
	{
		cin>>s[i].ID;
		cin>>s[i].score;
	}
	for(int i=1;i<=M;i++)
	{
		string q,x;
		cin>>q;
		cin>>x;
		cout<<"Case "<<i<<": "<<q<<" "<<x<<"\n";
		if(q=="1")
		{
			vector<student> v;
			for(int j=0;j<N;j++)
			{
				if(s[j].ID.substr(0,1)==x)
				{
					v.push_back(s[j]);
				}
			}
			sort(v.begin(),v.end(),cmp);
			if(v.size()!=0)
			{
				for(int k=0;k<v.size();k++)
				{
					cout<<v[k].ID<<" "<<v[k].score<<"\n";
				}
			}
			else
			cout<<"NA\n";
		}
		else if(q=="2")
		{
			int num=0,sum=0;
			for(int j=0;j<N;j++)
			{
				if(s[j].ID.substr(1,3)==x)
				{
					num++;
					sum+=s[j].score;
				}
			}
			if(num!=0)
			printf("%d %d\n",num,sum);
			else
			cout<<"NA\n";
		}
		else if(q=="3")
		{
			unordered_map<string,int> m;
			for(int j=0;j<N;j++)
			{
				if(s[j].ID.substr(4,6)==x)
				{
					m[s[j].ID.substr(1,3)]++;
				}
			}
			if(m.size()==0)
			cout<<"NA\n";
			else
			{
				unordered_map<string,int>::iterator it;
				vector<node> v;
				for(it=m.begin();it!=m.end();it++)
				{
					node leaf;
					leaf.num=it->second;
					leaf.set=it->first;
					v.push_back(leaf);
				}
				sort(v.begin(),v.end(),cmp1);
				for(int j=0;j<v.size();j++)
				{
					cout<<v[j].set<<" "<<v[j].num<<"\n";
				}
			}
		}
		else
		{
			cout<<"NA\n";
		}
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值