问题:统计字符串\(str\)中单词\(word\)出现的次数。已知字符串中的单词用一个空格或者多个空格隔开。
输入格式:有2行,第1行是字符串\(str\),第2行是不带空格的单词\(word\)。
分析:使用string来存储字符串\(str\)和单词\(word\)。可以通过string的find方法查找子串的方式统计单词出现次数,例如字符串和单词内容如下:
nice to meet you and how are you thank you very much you
初步想法是用find方法统计单词you在字符串nice to meet you and how are you thank you very much 出现次数:

#include<iostream>
#include<string>
using namespace std;
int main()
{
int cnt = 0;
string str,word;
getline(cin,str);
cin>>word;
//查找单词word第一次出现的位置
size_t pos = str.find(word);
while(pos != string::npos){ //查找到
cnt++;
//从pos+word.length()起继续查找单词word第一次出现的位置
pos = str.find(word,pos+word.length());
}
cout<<cnt<<endl;
return 0;
}
但是考虑下面的情况:
nice to meet you and how are you thank you and your friends very much you
因为your中也完整出现了单词you,也会被统计到。find方法是查找子串,如果字符串\(str\)中某个单词中完整出现了单词\(word\)(此外还有其他字符),用上面的方法也会认为单词\(word\)出现了一次导致统计结果出错!那么该如何解决问题呢?
其实我们可以用find方法统计字符串" "+str+" "中单词" "+word+" "出现的次数,这样处理就能有效避免上面的问题(注意体会并掌握这种处理方法):
#include<iostream>
#include<string>
using namespace std;
int main()
{
int cnt = 0;
string str,word;
getline(cin,str);
str = " "+str+" ";
cin>>word;
word = " "+word+" ";
//查找单词word第一次出现的位置
size_t pos = str.find(word);
while(pos != string::npos){
cnt++;
//从pos+word.length()起继续查找单词word第一次出现的位置
pos = str.find(word,pos+word.length());
}
cout<<cnt<<endl;
return 0;
}
如果我们用字符数组存储字符串,那么该如何统计单词出现次数呢?其实我们使用前一小节例题中的方法将字符串中的每个单词找出来:
#include<iostream>
#include<cstring>
using namespace std;
char str[1010];
int main()
{
char last = ' '; //记录上一个字符,体会这里默认值设置成空格字符的用途
fgets(str,sizeof(str),stdin);
int n = strlen(str); //n是字符串长度
int start = 0; //start记录单词首字符下标
//处理fgets输入字符串末尾可能额外附带的'\n'
if(n && str[n-1]=='\n') str[--n] = '\0';
for(int i=0;i<=n;i++){ //注意这里的条件是i<=n,而不是一般遍历字符串的i<n
//如果上一个字符是空格、当前字符不是空格,则找到一个新单词
if(last == ' ' && str[i] != ' '){
start = i; //记录找到的单词的首字符下标
}else if(last != ' ' && (str[i] == ' ' || str[i] == '\0')){ //单词结束
//从start到i-1是一个单词
for(int j=start;j<i;j++) cout<<str[j];
cout<<endl;
}
//last更新为当前字符,在下一次循环中就成了“上一个字符”
last = str[i];
}
return 0;
}
那么只需要判断每次找出来的单词是不是\(word\)就能统计单词\(word\)的数量了:
#include<iostream>
#include<cstring>
using namespace std;
char str[1010],word[1010];
int main()
{
int cnt = 0;
char last = ' '; //记录上一个字符,体会这里默认值设置成空格字符的用途
fgets(str,sizeof(str),stdin);
cin>>word;
int n = strlen(str); //n是字符串长度
int start = 0; //start记录单词首字符下标
//处理fgets输入字符串末尾可能额外附带的'\n'
if(n && str[n-1]=='\n') str[--n] = '\0';
for(int i=0;i<=n;i++){ //注意这里的条件是i<=n,而不是一般遍历字符串的i<n
//如果上一个字符是空格、当前字符不是空格,则找到一个新单词
if(last == ' ' && str[i] != ' '){
start = i;
}else if(last != ' ' && (str[i] == ' ' || str[i] == '\0')){ //单词结束
int j,k;
//从start到i-1是一个单词
//比较字符串str的start到i-1的字符与word的字符是否依次相等
for(j=start,k=0;j<i && word[k];j++,k++){
if(str[j] != word[k]) break;
}
//全部匹配相等,并且单词都匹配结束,那么匹配到单词word
if(j==i && word[k]=='\0') cnt++;
}
//last更新为当前字符,在下一次循环中就成了“上一个字符”
last = str[i];
}
cout<<cnt<<endl;
return 0;
}
NOIP学习小站