题目
编写一段程序,从标志输入中读取若干string对象并查找连续重复出现的单词。所谓连续重复出现的意思是:一个单词后面紧跟着这个单词本身。要求记录连续重复出现的最大次数以及对应的单词。如果这样的单词存在,输出重复出现的最大次数;如果不存在,输出一条信息说明任何单词都没有连续出现过。例如,如果输入是:
how now now now brown cow cow
那么输出应该表面单词
now
连续出现了3次。
分析
题目要求我们记录连续重复出现的最大次数和单词。那么,我们就需要保存每个单词(不重复)以及其对应的次数。我们有必要这样考虑:建立两个集合,一个集合中按顺序保存单词,另一个集合按顺序保存单词的次数。
我们可以采用C++的类模板来创建两个容器,来替代上面的两个集合,用来保存单词和次数。
vector<string> words; //保存单词
vector<int> counts; //保存每个单词出现的次数
接下来,我们需要处理输入的单词序列,将处理后的结果放在创建好的两个模板中。
这里有两个注意点
- 第一个单词如何处理?
- 最后一个单词如何处理?
为什么第一个单词需要单独处理呢?
其实这是和每个人的实现方式相关的。
比如我,在while
循环中,我们主要需要判断当前的输入单词current
和前一个单词 **before
**是否相等,如果相等,那么计数器cnt
加一;
if (current == before) cnt++; //重复次数加一
反之,我们便需要将前一个单词和次数分别加入words
和counts
中,并将current
赋值给before
,并重置cnt
,准备开始新一轮的比较。
string current,before; //用于遍历单词序列
int cnt = 1;
words.push_back(before); //添加结束重复的单词
counts.push_back(cnt); //添加单词的重复次数
before = current; //调换
cnt = 1; //重置
那么问题来了。
当我们输入第一个单词时,它没有前一个单词,相当于其与一个空字符串相比较,肯定不等,那么这时按照上面的做法,就需要把第一个单词和次数加入到words
和counts
中,而这显然是不对的。所以,我们需要单独处理第一个单词。
对于第一个单词,我们可以采用设置标志位的方式来解决。
bool flag = true;
if(flag) //第一个单词单独处理,仅仅进行交换,然后复位标志位
{
before = current;
flag = false;
}
那最后一个单词呢?
首先来看看我们上面写的程序,思考最后一个单词会怎么样?
while(cin >> current)
{
if (current == before) cnt++; //重复次数加一
else
{
if(flag) //第一个单词单独处理
{
before = current;
flag = false;
}
else
{
words.push_back(before); //添加结束重复的单词
counts.push_back(cnt); //添加单词的重复次数
before = current; //调换
cnt = 1; //还原
}
}
}
不论最后一个单词和倒数第二个单词是否相等,最后一个单词都是不会加入words
和counts
的,因为前一个单词是否加入,是由后一个单词决定的。而最后一个单词没有后一个单词,所以也必然需要特殊处理。怎么处理呢?
很简答啊,直接添加就好了啊!
words.push_back(before); //处理最后一个数据
counts.push_back(cnt);
好了,目前为止,我们已经将单词和次数处理好了。接下来就是要找最大的次数。
这里我们使用迭代器+for循环来实现。
vector<int>::iterator num = counts.begin(); //begin()返回指向counts第一个元素的指针
int max = 1; //最大值初始化为1 (因为每个单词至少出现一次)
for(num;num != counts.end();++num) //end()返回尾后指针
{
if(*num > max)
max = *num; //找到最大值
}
那么找到最大值之后,就到了最后的输出阶段了。
这里有两种情况
- max 为 1
- max 不为 1
当max 为 1 时,说明输入的单词序列中,每个单词都只出现了一次。
if(max == 1)
cout << "该单词序列中没有连续重复出现的单词!"<< endl;
当 max 不为 1 时,则输出对应的单词及其最大连续重复出现的次数。
for(int i = 0;i < counts.size();++i) // size()返回容器的长度
{
if(counts[i] == max) // 匹配到最大值
cout<<"单词"<<words[i]<<"连续出现的次数为:"<<max<<"次!"<<endl;
}
最后对程序进行汇总:
#include <iostream>
#include <vector>
#include <string>
void func5_14()
{
vector<string> words; //保存单词
vector<int> counts; //保存每个单词出现的次数
string current,before; //用于遍历单词序列
cout << "请输入一系列单词: " << endl;
int cnt = 1;
bool flag = true;
while(cin >> current)
{
if (current == before) cnt++; //重复次数加一
else
{
if(flag) //第一个单词单独处理
{
before = current;
flag = false;
}
else
{
words.push_back(before); //添加结束重复的单词
counts.push_back(cnt); //添加单词的重复次数
before = current; //调换
cnt = 1; //还原
}
}
}
words.push_back(before); //处理最后一个数据
counts.push_back(cnt);
vector<int>::iterator num = counts.begin();
int max = 1;
for(num;num != counts.end();++num)
{
if(*num > max)
max = *num; //找到最大值
}
if(max == 1)
cout << "该单词序列中没有连续重复出现的单词!"<< endl;
else
{
for(int i = 0;i < counts.size();++i)
{
if(counts[i] == max)
cout<<"单词"<<words[i]<<"连续出现的次数为:"<<max<<"次!"<<endl;
}
}
}
测试程序
我们采用以下几组单词序列进行测试
how now now now brown cow cow
how now cow
第一组
第二组
可见,程序运行正常。
小结
上面这道习题的难度算是中等,主要涉及了以下知识点:
- 模板的使用、push_back()函数等
- 迭代器的使用,size()函数
- while 、if 条件语句等
- 程序逻辑,标志位等等
ps:这道题的实现方式有很多,我这只是其中一种,且有很大的改进空间。