这又是一道成功加入“容易吗”系列的基础题= =原本很简单,可是我一开始太大意看错了题,以为是让输出该单词是第几个单词,实际上应该输出该单词的首字母在第几个位置;改过后只得了二十分,看了一组数据,原来第一个单词前面可以有前导空格——幸亏其他单词前没有,否则还真不知道怎么办;实现的时候又出了各种问题。于是我决定总结一下。
题目:
给定一个单词,请你输出它在给定的文章中出现的次数和第一次出现的位置。注意:匹配单词时,不区分大小写,但要求完全匹配,即给定单词必须与文章中的某一独立单词在不区分大小写的情况下完全相同(参见样例1 ),如果给定单词仅是文章中某一单词的一部分则不算匹配(参见样例2 )。
输入格式: 输入文件名为stat.in ,2 行。 第1 行为一个字符串,其中只含字母,表示给定单词; 第2 行为一个字符串,其中只可能包含字母和空格,表示给定的文章。输出格式: 输出文件名为stat.out 。 只有一行,如果在文章中找到给定单词则输出两个整数,两个整数之间用一个空格隔开,分别是单词在文章中出现的次数和第一次出现的位置(即在文章中第一次出现时,单词首字母在文章中的位置,位置从 0 开始);如果单词在文章中没有出现,则直接输出一个整数-1。
1≤ 单词长度≤10。1≤ 文章长度≤1,000,000。
二话不说,先上代码
//tongjidancigeshu#include<iostream>#include<string>#include<cctype>//for tolower#include<cstdio>using namespace std;inline string change(string s){//wxjlzbcd神犇表示,加inline后变成内联函数,内联到宏中,可以稍微加速,暴搜可用,但是我不大了解,慢慢学习for (int i=0;i<s.length();i++) s[i]=tolower(s[i]);return s;//don't forget//刚开始竟然忘了return s,导致出现错误好像是访问无效内存rewritten} int main(){freopen("1.txt","r",stdin);//freopen输入输出,粘代码党记得删除O(∩_∩)O~再次强化要用cstdio头文件freopen("2.txt","w",stdout);string point,s,words;//point记录要查找的单词,s是文章整体读入,words是截取的文章中的单个单词getline(cin,point);//注意:point一定要用getline读入!否则下一个getline(cin,s)会直接读取point后的回车,导致s=''!point=change(point);//tolower only use for single char tolower位于cctype头文件中,只用于单个字符getline(cin,s);//if the third position is empty it's \n= =关于这一点,正文中会介绍↓s=change(s);int i,pos=0,anspos=-1,ans=0;//anspos要设为-1,如果设为0,由于初始位置也是0,初始位置就是第一个单词的话会出现判断错误for (i=0;i<s.length();i++){if (s[i]==' '){//每次找到空格,截取空格前面的单词比较words=s.substr(pos,i-pos);//notice the usage!注意s.substr的用法,稍后介绍↓if (point==words){if (anspos==-1) anspos=pos;//免去布尔变量的使用ans++;}pos=i+1;} }if (anspos==-1) cout<<anspos<<endl;else cout<<ans<<' '<<anspos<<endl;return 0;}为防止大家看不懂我不标准的英文注释,代码注释采用中英双语= =
关于代码中提到的两点:
1.getline()
关于这一点,这里有一份相当好的资料,来自新浪博主sundowner,他在博客园也有博客
原文地址:
作者博客园博客:
作者所言如下:
学习C++的同学可能都会遇到一个getline()函数,譬如在C++premer中,标准string类型第二小节就是“用getline读取整行文本”。书上给的程序如下:
int main()
{
string line:
while(getline(cin,line))
cout<<line<<endl;
return 0;
}
大家会发现运行时怎么也跳不出循环,甚至会发生各种莫名其妙的错误。这是为什么呢?在这里我给大家做一个详细的讲解。
首先给大家介绍一下getline()函数(个人觉得百度百科给的果断不够详细)
大家百度会发现getline()的原型是istream& getline ( istream &is , string &str , char delim );
其中 istream &is 表示一个输入流,譬如cin;string&str表示把从输入流读入的字符串存放在这个字符串中(可以自己随便命名,str什么的都可以);char delim表示遇到这个字符停止读入,在不设置的情况下系统默认该字符为’\n’,也就是回车换行符(遇到回车停止读入)。给大家举个例子:
string line;
cout<<"please cin a line:"
getline(cin,line,’#’);
cout<<endl<<"The line you give is:"line;
那么当我输入"You are the #best!" 的时候,输入流实际上只读入了"You are the ",#后面的并没有存放到line中(应该是在缓冲区里吧)。然后程序运行结果应该是这样的:
please cin a line:You are the #best!
The line you give is:You are the
而且这里把终止符设为#,你输入的时候就算输入几个回车换行也没关系,输入流照样会读入,譬如:
please cin a line:You are the best!
//这里输入了一个回车换行
Thank you!
# //终止读入
The line you give is:You are the best!
//换行照样读入并且输出
Thank you!
以上就是getline()函数一个小小的实例了。
那么如果把getline()作为while的判断语句会怎么样呢?
让我们一起来分析一下while(getline(cin,line))语句
注意这里默认回车符停止读入,按Ctrl+Z或键入EOF回车即可退出循环。
以诚感人者,人亦诚而应。