[NOIP2011]统计单词数
[NOIP2011]统计单词数
https://ac.nowcoder.com/acm/problem/16585
分析
首先分别将两个字符串输入
std::getline(std::cin, p);
std::getline(std::cin, s);
分别小写化,使用tolower
函数将字符串的每一个字符变成小写。
遍历字符串s
int len_s = s.length();
for (int i = 0; i < len_s; ++i)
利用s[i]与p首字母进行匹配,不匹配的情况不能进入循环。
若匹配,则逐字符匹配,同时声明两个变量,m, n分别记录s和p的位置,但是不改变i的大小。
int m = i, n = 0;
while (s[m] == p[n] && p[n]) //p[n]表示p最后一个字母用完跳出
{
m++, n++;
}
累加不匹配就跳出。
如果p还没有遍历完就跳出,在s[i]与p首字母匹配前定义一个变量fff
记录p是否用完。
fff = ( p[n] )? 0 : 1;
如果p遍历完了,就让结果加1。
note: 结尾应该是空格或者'\0'
,才能证明完全匹配。
if (fff) {
if (s[m] != ' ' && s[m] != '\0') continue;
if (ans == 0) {
pos = i; //pos记录首次匹配位置
}
++ans;
i += len_p;//完全匹配字母已经遍历完了,直接跳过,减少重复遍历。
}
note: 刚才是结尾是空格,但是突然发现上面的程序并不能通过。
例如:
t
tt t
我的输出
3 0
而正确输出
1 3
note: 接上面note,不仅结尾是空格,而且开头是空格。
在这种情况下,如果首字母匹配,前一个字符是空格,可以继续遍历,如果不是,说明它也不可能是匹配,因为i += len_p;//完全匹配字母已经遍历完了,直接跳过,减少重复遍历。
在根据if (s[m] != ' ' && s[m] != '\0') continue;
说明不匹配的刚刚跳出,所以我需要继续往后走,直到走到空格。
if (s[i - 1] >= 'a' && s[i - 1] <= 'z') {
while (s[i] >= 'a' && s[i] <= 'z') {
i++;
}
}
完整代码:
#include <iostream>
#include <ctype.h>
#include <algorithm>
#include <string>
int main()
{
std::string p, s;
std::getline(std::cin, p); std::getline(std::cin, s);
int len_p = p.length();
int len_s = s.length();
for (int i = 0; p[i]; i++)
{
p[i] = tolower(p[i]);
}
for (int i = 0; s[i]; i++)
{
s[i] = tolower(s[i]);
}
//std::cout << p << "\n";
//std::cout << s << "\n";
int pos, ans = 0;
for (int i = 0; i < len_s; ++i) {
int fff = 0;
if (s[i] == p[0]) {
if (s[i - 1] >= 'a' && s[i - 1] <= 'z') {
while (s[i] >= 'a' && s[i] <= 'z') {
i++;
}
}
int m = i, n = 0;
while(s[m] == p[n] && p[n]) {
m++,n++;
}
//std::cout << n << " " << int( p[n] ) << "\n";
fff = ( p[n] ) ? 0 : 1;
if (fff) {
if (s[m] != ' ' && s[m] != '\0') continue;
if (ans == 0) {
pos = i;
}
ans++;
i += len_p;
}
}
}
if (ans > 0) {
std::cout << ans << " " << pos;
}
else {
std::cout << "-1";
}
return 0;
}