NOIP学习小站
西安交通大学附属中学航天学校

字符串例题——统计单词数量

问题:统计长度不超过1000的字符串中的单词数量。字符串中的单词用一个或者多个空格隔开。

分析:输入的字符串包含空格,不能简单地使用cin或者scanf输入。可以直接遍历字符串中的字符,遍历过程中统计单词首字符的数量,单词首字符的特点是:当前字符不是空格,上一个字符是空格。

#include<iostream>
#include<cstring>
using namespace std;
char str[1010];
int main()
{
	int cnt = 0;
	char last = ' ';	//记录上一个字符,体会这里默认值设置成空格字符的用途 
	fgets(str,sizeof(str),stdin);
	//遍历字符串中的字符
	for(int i=0;str[i];i++){      //条件str[i]是str[i]!='\0'的简写
		//如果上一个字符是空格、当前字符不是空格,则找到一个新单词
		if(last == ' ' && str[i] != ' '){
			cnt ++;
		}
		//last更新为当前字符,在下一次循环中就成了“上一个字符”
		last = str[i];
	}
	cout<<cnt<<endl;
	return 0;
} 

编译运行,发现基本上能解决问题,但是有一个小小的BUG——如果输入的字符串末尾有空格,那么统计出来的单词数量比实际单词数量多1个。原因是fgets函数输入字符串时,字符串的末尾可能会额外多一个'\n'。如下图所示,此时程序也会认为找到了一个新单词。

#include<iostream>
#include<cstring>
using namespace std;
char str[1010];
int main()
{
	int cnt = 0;
	char last = ' ';	//记录上一个字符,体会这里默认值设置成空格字符的用途 
	fgets(str,sizeof(str),stdin);
	//遍历字符串中的字符,考虑了fgets输入字符串末尾可能额外附带的'\n'
	for(int i=0;str[i] && str[i] != '\n';i++){
		//如果上一个字符是空格、当前字符不是空格,则找到一个新单词
		if(last == ' ' && str[i] != ' '){
			cnt ++;
		}
		//last更新为当前字符,在下一次循环中就成了“上一个字符”
		last = str[i];
	}
	cout<<cnt<<endl;
	return 0;
} 

当然也可以使用string存储字符串,使用getline函数输入有空格的字符串到string:

#include<iostream>
#include<string>
using namespace std;
int main()
{
	int cnt = 0;
	char last = ' ';	//记录上一个字符,体会这里默认值设置成空格字符的用途 
	string str;
	getline(cin,str); 
    //遍历string的每个字符 
	for(size_t i=0;i<str.length();i++){
		//如果上一个字符是空格、当前字符不是空格,则找到一个新单词
		if(last == ' ' && str[i] != ' '){
			cnt ++;
		}
		//last更新为当前字符,在下一次循环中就成了“上一个字符”
		last = str[i];
	}
	cout<<cnt<<endl;
	return 0;
} 

其实本问题最简单的处理方法是使用循环输入字符串的方式将用空格隔开的单词依次输入:

#include<iostream>
#include<string>
using namespace std;
int main()
{
	int cnt = 0;
	string str;
    while(cin>>str) cnt++;
	cout<<cnt<<endl;
	return 0;
} 

虽然在命令行状态下运行使用标准输入时,需要额外输入CTRL+Z并回车才能结束输入,和前面程序输入回车直接结束输入不相同,但是测评时从文件读入字符串,上述程序的输入效果时一致的。