PTA7-32 说反话-加强版(20 分)超级详解

给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。
输入格式:
测试输入包含一个测试用例,在一行内给出总长度不超过500 000的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有区分)组成的字符串,单词之间用若干个空格分开。
输出格式:
每个测试用例的输出占一行,输出倒序后的句子,并且保证单词间只有1个空格。
输入样例:
Hello World   Here I Come
输出样例:

Come I Here World Hello

本人此题完全通过总共花了145 min,前40min内早已得到19分,但还是差1分在输出格式上,光想这一个1分的测试点就花了几十分钟,然后以为是除了单词和单词间的空格其他两头的空格如果有的话都要输出,又花几十分钟写了一个算法,结果测试都是错,又花了几十分钟反思总结,终于写出正确的算法。。

本题的难点在于如何处理多个空格,以及最难的,如果处理最后一个单词的输出并保证之后完全没有空格。先来分析下本题,读题,首先抓细节,本题的细节整理如下:

1.英语,说明只有字母。

2.句中所有单词的顺序颠倒输出,即如果将每个单词看成一个数组内的元素,那么就是从数组末端输出到前端,而不是将单词内的字母倒序,主语是“句子”,所以是将“句子”这个“组”内的各个“元素”倒序输出,“元素”内的内容当然不会改变。

3.字符串由若干个单词和空格组成,说明输入会有很多空格,c++语言用getline来接收空格

4.保证单词间只有一个空格,也就是说单词间如果有多余空格你要删除或者忽略

5.结合2,4两个重要细节,可以得到如下结论:

输出原字符串的所有单词和单词间的一个空格,其余空格统一忽略或删除。

本人就是没有完全处理好上述结论导致出现奇怪的1分错误提示,格式错误,原因就是多输出了一个空格。

好,抓完细节,再来利用细节设计解题方案:

1.从末尾倒上来遍历字符串,记录单词字母个数,如果碰到第一个空格,输出之前的单词,并清空字母计数器,用一个标识标记已经碰到过一个空格了,于是继续遍历,如果有多余空格,因为标识的作用则会忽略,直到碰到下一个单词,如此往复。

2.特殊情况处理,最后一个单词需要单独输出,最后一个单词前面可能有空格,可能没有空格,如果有空格,那么在前一次循环遍历时会输出这个单词,但是前一个循环遍历输出每一个单词的时候都是带有空格一起输出的,如果是最后一个单词,怎么让前一个循环知道它碰到这个单词而不需要输出空格呢?

3.我们先看最后一个单词前面没有空格的情况,这种情况必须从字符串开头输出整个单词,利用前一个循环留下来的计数器就可以实现,因为前一个循环的计数器最终的值就是最后一个单词的字母个数。

4.我们再来看最后一个单词前面有空格的情况,我们要想让前一个循环知道什么时候不输出空格,我们必然会增设一个辅助标识,如果想要统一最后一个单词的两种情况的算法,那么这个标识定为最后一个单词首字母的位置就再合适不过了。

5.于是我们只需要在遍历操作开始前再增设一个遍历操作,从开头起往后寻找第一个不为空格的字符,这个字符的位置就是我们要找的位置,即最后一个单词的首字母的位置。保存这个位置,在接下来的遍历中作为是否为最后一个单词的标志,如何实现这个判定呢?

6.很简单,只要碰到当前字符为空格,检查这个空格的后一个字符位置是不是我们一开始保存的最后一个单词的首字母位置,如果是,则不输出空格。

7.最后,从保存的位置开始,利用前面留下来的字符计数器输出最后一个单词,AC!

以下是具体代码:

#include<iostream>
#include<string>
using namespace std;
int main()
{
	string s;
	int cnt_ch=0,flag=1,start=0;/*定义字符计数器,单空格标识,最后一个单词的起始下标*/
	/*其中字符计数器,最后一个单词的起始下标必须初始化为0,单空格标识为了安全起见初始化为1*/
	getline(cin,s);
	for(int i=0;i<s.length();i++)/*寻找最后一个单词的起始下标*/
	if(s[i]!=' ')
	{
		start=i;
		break;
	}
	for(int i=s.length()-1;i>=0;i--)/*从后往前输出单词*/
	{
		if(s[i]!=' ')/*只要当前字符不为空格,单空格标识为0,字符计数器自增1*/
		{
			flag=0;
			cnt_ch++;
		}
		else if(!flag)/*如果当前字符为空格且单空格标识为0*/
		{
			flag=1;/*标识置为1,说明单词间已经存在一个空格*/
			for(int j=i+1;j<i+1+cnt_ch;j++)/*从当前字符的后一个字符开始输出字符个数长度的单词*/
			cout<<s[j];
			if(i+1!=start)/*如果当前空格的后一个字符不是最后一个单词的首字母,
			则输出空格,即最后一个单词后面不输出空格*/
			cout<<' ';
			cnt_ch=0;
		}
	}
	for(int i=start;i<start+cnt_ch;i++)/*输出最后一个单词*/
	cout<<s[i];
	return 0;
}
综上,解题,不仅要处理好细节,虽然处理好细节你已经能拿大部分分数了,但是如果要拿满分,则需要多加留意特殊情况的处理,仔细分析,最终,才能摘下AC的“头衔”。

猜你喜欢

转载自blog.csdn.net/qq_37729102/article/details/80682747