【题目描述】
给出一个由O和X组成的串(长度为1~80),统计得分。每个O的得分为目前连续出现的O的个数,X的得分为0。例如,OOXXOXXOOO的得分为1+2+0+0+1+0+0+1+2+3。
输入第一行表示有n个字符串,后续是n行字符串。
【样例输入】
5
OOXXOXXOOO
OOXXOOXXOO
OXOXOXOXOXOXOX
OOOOOOOOOO
OOOOXOOOOXOOOOX
【样例输出】
10
9
7
55
30
【题目来源】
刘汝佳《算法竞赛入门经典 第2版》习题3-1 得分(Score, ACM/ICPC Seoul 2005, UVa1585)
【解析】
本题是一道得分累加问题,题目不难,只需定义两个变量:
①计数器cnt,用于计算已经连续出现的“O”的个数;
②累加器sum,用于计算串的得分。
思路就是对输入串的字符进行遍历,如果遇到“O”就cnt++,如果遇到“X”就将cnt重置为0,然后每次将cnt加到sum中即可。
1.用scanf输入字符串
#include<stdio.h>
char s[85];
int main(){
int n;
char c;
scanf("%d", &n);
while(n--){
int sum=0, cnt=0;
scanf("%s", s);
for(int i=0; i<strlen(s); i++){
if('O'==s[i]) cnt++;
else cnt=0;
sum += cnt;
}
printf("%d\n", sum);
}
return 0;
}
代码说明:
1.代码精简。for循环中的代码可以进一步精简,就是将cnt的自加与sum的累加合成一个语句,改后代码如下:
if('O'==s[i]) sum += ++cnt;
else cnt=0;
注意,因为要返回自加后的值,此时就需要用++cnt,不能用cnt++(关于二者的区别参见“找不到北的i++”一文https://blog.csdn.net/jjmhx/article/details/136995419)。
2.效率问题。你是否发现,代码中有一处写法效率低下。就是在“程序找茬:统计字符个数问题”一文中提到的“重复调用函数”问题,strlen函数放在for循环中会导致重复计算字符串的长度。解决方法就是预先将函数的值赋给一个变量,在for循环中直接用这个变量。
3.头文件缺失。在“程序找茬:统计字符个数问题”一文中已提到,不引用<string.h>头文件程序也能执行(只是会有警告),但是在Online Judge - Home网站中提交代码反馈错误。
如果因为这个问题丢分实属不值,所以还是乖乖加上该加的头文件吧。
2.用getchar输入字符
老金想着秀一下“编技”,打一开始就想用getchar读取字符,这样就用不着数组了,没想到输出了意想不到的结果。
最开始编的代码是只是针对一个字符串的情况,运行没有任何问题。代码如下:
#include<stdio.h>
int main(){
char c;
int sum=0, cnt=0;
while((c=getchar())!='\n'){
if('O'==c) cnt++;
else cnt=0;
sum += cnt;
}
printf("%d\n", sum);
return 0;
}
没想到改成多组字符串时出现了问题,代码如下:
#include<stdio.h>
int main(){
int n;
char c;
scanf("%d", &n);
while(n--){
int sum=0, cnt=0;
while((c=getchar())!='\n'){
if('O'==c) cnt++;
else cnt=0;
sum += cnt;
}
printf("%d\n", sum);
}
return 0;
}
运行结果:
居然刚输入数字5就直接输出了结果!什么情况?
经过调试老金搞明白了原因,问题出在了输入缓冲区。
执行到scanf("%d", &n)这条语句时,实际在键盘输入的是两个字符:一个是’5’,一是个换行符’\n’。 scanf函数只是读取了字符“5”,并没有读入换行符。所以这条语句执行完后,换行符还留在输入缓冲区。因此,getchar第一次读取的是换行符,循环条件不满足,直接输出sum的初始值0。
搞清原因,解决起来就好办了,在while((c=getchar())!='\n')前加一条语句把换行符读取掉就可以了。增加代码如下:
getchar(); //清空缓冲区的换行符
所以,在使用getchar()时要注意,如果前面使用了scanf函数,别忘了带走它留下的那片云彩。