PAT (Basic Level) Practice 1009 说反话

一、概述

输入由一个空格隔开的多个单词,反序输出。

很简单很直观的一道题,我却在上面栽了快两小时。最终也只是过了两个测试点,测试点1和2,0和3死活过不去。

简直气死。

二、分析

方法1、我的方法

由于之前码的代码大多数在单片机上跑,所以对空间敏感度十分敏感,能少用数组就少用。所以思路如下:

利用while-EOF来将整个句子输入到字符数组中。

char sen[81];
int count[81] = { 0 };
int i = 0;
int k = 1;
while (scanf("%c", &sen[i]) != EOF)
{
	if (sen[i] == ' ')
	{
		i++;
		count[k] = i;
		k++;
	}
	else
		i++;
}

再开一个整形数组,用于记录各个单词首字母的下标,在输入遇到空格时刚好将整形数组初始化。

输出就是从最后一个单词的首字母开始输出,遇到空格不再输出。

然后判断是不是第一个单词,不是则输出空格,是则不输出。

//sen[i] = ' ';
sen[i - 1] = ' ';//debug时使用
int m;
if (i == 0)
	return 0;
else
{
	for (m = k - 1; m >= 0; m--)
	{
		i = 0;
		while (sen[count[m] + i] != ' ')
		{
			printf("%c", sen[count[m] + i]);
			i++;
		}
		if (sen[0] == ' ')
		{
			if (m > 1)
				printf(" ");
		}
		else if (m>0)
			printf(" ");
	}
}

为什么debug时要和在oj上不同呢?因为debug时,对于eof,要按如下方式在控制台输入

另起一行,ctrl+z,回车,ctrl+z,回车。

这样会多打一个回车,用这个方法盖住多的回车。

很不喜欢这种读入数据的方法,debug很麻烦,很容易弄晕弄混。

蛮复杂的,但是空间复杂度很小,只需要一个额外的整形数组,40个int大小就够,自以为算法不错。

实际可不是这样,差点把我气死。debug了一个多小时,试了许多情况:

无单词输入,则输出应该什么都没有;

仅一个单词输入,则仅一个单词输出;

多个单词输入,最普遍的情况;

一个长为80字符的单词输入;

最丧心病狂的,题目说句尾没有多余空格,没说句首没有啊,我特意判断了这一点;

都试过了,还是过不来了测试点。无奈,只好换算法。

方法2、使用二维字符数组加字符输入输出

这是网上最普遍的算法。用空格作为分隔符,将不同单词放在不同行里。

多数人用的是gets函数,但是pta的gcc不允许该函数,只好用fgets函数,这个函数有三个变量,字符数组变量,长度,从哪输入,要是键盘就用stdin。

char sen[90];
fgets(sen,90,stdin);
int length;
length = strlen(sen);
length--;

这个函数与gets的区别在于,gets遇回车结束输入,不吃回车,加'\0',而fgets遇回车结束,回车作为结尾。这样一来,由于回车是咱们不需要的,就需要把长度减一了。

还有,gets在VS2015中不能用,要用gets_s。事儿真多。

方法3、利用%s

是最短的代码,利用了scanf使用%s时遇空格自动停止输入的特性,简直完美。

输出也可以使用%s,可以直接输出一行。

三、总结

学到了很多,如控制台如何输入EOF结束循环,最重要的是多种输入字符串的方法。还有空间复杂度在一定程度上并不重要,几十几百的二维数组很正常。另外,算法越复杂,可能出错的地方越多,重剑无锋,大巧不工。

PS:代码如下

方法一:测试点0和3过不去

#include<stdio.h>
int main()
{
	char sen[81];
	int count[81] = { 0 };
	int i = 0;
	int k = 1;
	while (scanf("%c", &sen[i]) != EOF)
	{
		if (sen[i] == ' ')
		{
			i++;
			count[k] = i;
			k++;
		}
		else
			i++;
	}
	//sen[i] = ' ';
	sen[i - 1] = ' ';//debug时使用
	int m;
	if (i == 0)
		return 0;
	else
	{
		for (m = k - 1; m >= 0; m--)
		{
			i = 0;
			while (sen[count[m] + i] != ' ')
			{
				printf("%c", sen[count[m] + i]);
				i++;
			}
			if (sen[0] == ' ')
			{
				if (m > 1)
					printf(" ");
			}
			else if (m>0)
				printf(" ");
		}
	}
}

方法二:

#include<stdio.h>
#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>

using namespace std;

int main()
{
	char sen[90];
	fgets(sen,90,stdin);
	int length;
	length = strlen(sen);
	length--;
	char word[80][80] = { 0 };
	int i;
	int row = 0;
	int j = 0;
	for (i = 0; i < length; i++)
	{
		if (sen[i] != ' ')
		{
			word[row][j] = sen[i];
			j++;
		}
		else
		{
			sen[i] = '\0';
			row++;
			j = 0;
		}
	}
	for (i = row; i >= 0; i--)
	{
		printf("%s", word[i]);
		if (i > 0)
			printf(" ");
	}
}

方法三:

#include<stdio.h>

int main()
{
	char sen[80][80];
	int row=0;
	while (scanf("%s", &sen[row]) != EOF)
		row++;
	int i;
	for (i = row - 1; i >= 0; i--)
	{
		printf("%s", sen[i]);
		if (i != 0)
			printf(" ");
	}
	/*char a[80] = { 0 };
	char b[80] = { 0 };
	gets_s(a);
	fgets(b, 80, stdin);*/
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值