题目描述
一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数。
现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给定的文章中出现的次数和第一次出现的位置。注意:匹配单词时,不区分大小写,但要求完全匹配,即给定单词必须与文章
中的某一独立单词在不区分大小写的情况下完全相同(参见样例1 ),如果给定单词仅是文章中某一单词的一部分则不算匹配(参见样例2 )
输入描述:
共 2 行。
第 1 行为一个字符串,其中只含字母,表示给定单词;
第 2 行为一个字符串,其中只可能包含字母和空格,表示给定的文章
输出描述:
一行,如果在文章中找到给定单词则输出两个整数,两个整数之间用一个空格隔开,分别是单词在文章中出现的次数和第一次出现的位置(即在文章中第一次出现时,单词首字母在文章中的位置,位置从 0 开始);如果单词在文章中没有出现,则直接输出一个整数 -1。
示例1
To
to be or not to be is a question
2 0
输出结果表示给定的单词 To 在文章中出现两次,第一次出现的位置为0。
示例2
to
Did the Ottoman Empire lose its power at that time
-1
表示给定的单词 to 在文章中没有出现,输出整数-1。
解答
这个题目是一个字符串的综合题,在读入就有坑,第一行key单词后面的"\n"一定要处理掉,本人使用了两次读入,在读取第二行时就会将第一次读取的覆盖。 偷懒了很多天以后,决定将cin改为两个getline,提高代码可读性。
1、void convert(string test);函数用来将所有的字符全部改变成小写字符,看不懂就该看看书了哈;
2、题目本身不难,重点是要考虑到边界的处理,比如: i 和 mpi 这种是不匹配的,但是用搜索单个字母是很容易会计算进去,因为你的条件设定的不合理。
3、针对第一词出现的位置,利用变量demo来记录,所以只要flag不等于0,就说明第一词尚未出现,demo=i;继续改变demo,直到flag > 0,说明第一词已经出现,就不用改变demo了,需要关注位置从零开始的哈~
if(flag == 0){demo = i;}
3、我是这么做的,条件循环(data[i] != '\0')来完成对第二行data的搜索,然后就用条件判断(key[j] == data[i] )来判断第一个字符是否匹配,如果匹配,我就来检测(data[i+1] ==空格/或者是结束符 and key[j+1]==结束符),如果key后一项是结束符,并且data下一项为空格,说明两个单词完全相等,判断data下一项是不是结束符,非常有必要,否则就会读取非法内存!!!这个是核心。
4、要注意,我们是以核心来单词为单位来判断,所以一旦key和data的某一个单词不匹配,你应该跳过该单词剩下的所有字母,使用while(data[i++] != ' ' && data[i] != '\0'){} 来跳过剩下的字母,直到遇到空格或者data的最后一项,不能忘记j=0,key也要从头开始检测。
#include <iostream> #include <string> using namespace std; void convert(string &p); int main(void) { string key; string data; int flag = 0; int demo = -1; getline(cin,key); getline(cin,data); convert(data); convert(key); int i = 0; int j = 0; while(data[i] != '\0') { if(flag == 0) { demo = i; } while(data[i] == key[j]) { if(key[j+1] == '\0' && (data[i+1] == ' ' || data[i+1] == '\0')) { flag++; break; } else { j++; i++; } } j = 0; while(data[i++] != ' ' && data[i] != '\0') { } } if(flag != 0) cout << flag << " " << demo; else cout << -1; return 0; } void convert(string &p) { int i = 0; while(p[i] != '\0') { if(p[i] >= 'A' && p[i] <= 'Z' ) p[i] += 32; i++; } }