C语言PAT刷题 - 1014 福尔摩斯的约会

作者的话:若有朋友复制代码去PAT试着运行遇到问题的:
1.可能是格式问题,可以先把从本站复制的代码粘贴到记事本,再把记事本里的代码复制,然后粘贴到PAT的代码区,提交本题回答,应该就可以了;
2.可能是注释原因,PAT有时候检测到注释会编译错误,所以可以先把注释删了,再进行提交回答。
3.可能是作者当初根据题目写出来的代码仍存在一些疏漏,而恰好当时的测试机制没那么完善,没检测出问题。后面测试机制有所更新,故出现问题,若有相关需要的可以评论区留言或私信作者,我看到的话会去再查一下疏漏之处,然后更新文章。

一、题目描述
大侦探福尔摩斯接到一张奇怪的字条:
我们约会吧!
3485djDkxh4hhGE
2984akDfkkkkggEdsb
s&hgsfdk
d&Hyscvnm
大侦探很快就明白了,字条上奇怪的乱码实际上就是约会的时间星期四 14:04,因为前面两字符串中第 1 对相同的大写英文字母(大小写有区分)是第 4 个字母 D,代表星期四;第 2 对相同的字符是 E ,那是第 5 个英文字母,代表一天里的第 14 个钟头(于是一天的 0 点到 23 点由数字 0 到 9、以及大写字母 A 到 N 表示);后面两字符串第 1 对相同的英文字母 s 出现在第 4 个位置(从 0 开始计数)上,代表第 4 分钟。现给定两对字符串,请帮助福尔摩斯解码得到约会的时间。
输入格式:
输入在 4 行中分别给出 4 个非空、不包含空格、且长度不超过 60 的字符串。
输出格式:
在一行中输出约会的时间,格式为 DAY HH:MM,其中 DAY 是某星期的 3 字符缩写,即 MON 表示星期一,TUE 表示星期二,WED 表示星期三,THU 表示星期四,FRI 表示星期五,SAT 表示星期六,SUN 表示星期日。题目输入保证每个测试存在唯一解。
输入样例:
3485djDkxh4hhGE
2984akDfkkkkggEdsb
s&hgsfdk
d&Hyscvnm
输出样例:
THU 14:04

二、解题思路
读题:

按照某种解密规则对输入的四串乱码进行解密,并根据输出格式输出约会时间。
解密规则:对前两个字符串进行比对,在两个字符串中,第一对相同的大写英文字母在26个英文字母中的次序对应约会的日期在一个星期中的次序,如第一个字母A代表星期一,第二个字母B代表星期二,以此类推。同样在前两个字符串中,第二对相同的字符对应几点(0-9对应0点-9点,A-N对应10-23点)。
对后两个字符串进行比对,第一对相同的英文字母在字符串中的序号(这里的序号从0开始算,如第一个字符序号为0,第二个字符序号为1,以此类推)对应第几分钟(序号为0对应整点,序号为1对应第一分钟)。
思路:
1.定义需要的变量(实际解题时是先定义认为需要用到的变量,后面遇到问题需要新定义变量时再回到上头来定义新的变量),从键盘接收4个字符串存入字符数组a1,a2,b1,b2中;
2.计算四个字符串的长度,后面用于循环条件控制循环次数;
3.设置循环,对四个字符串按两个一组,对他们进行比对。第一个字符串要找到两对相同的字符。为避免混乱,使用变量flag进行区分。flag为0,时,寻找第一对符合条件的字符,找到后按规则进行相应的处理;flag为1时,寻找第二对符合条件的字符,找到后按规则进行相应的处理,并结束第一组字符串的检测。
4.对于第二组字符串,也是一样的,对各自的次序进行比对,符合条件的按规则进行相应的处理。

三、具体实现
0.标准C源程序框架

#include <stdio.h>
#include <string.h>//因为后面要用到字符串长度计算函数,故引入头文件<string.h>
int main()
{
	return 0;
}

1.定义需要的变量(实际解题时是先定义认为需要用到的变量,后面遇到问题需要新定义变量时再回到上头来定义新的变量),从键盘接收4个字符串存入字符数组a1,a2,b1,b2中;

	char a1[61], a2[61], b1[61], b2[61];//a1,a2储存前两组字符串;b1,b2储存后两组字符串
	int i = 0;//循环变量,用于对字符串进行一一比对
	int flag = 0;//旗帜变量,用于指示正在第一组字符串中寻找第几对符合条件的字符
	int a1_length, a2_length, b1_length, b2_length;//保存四个字符串的长度
	do {        //接收第一个字符串,并添加字符串结束标志'\0',避免后面计算长度时因没有'\0'出错
		scanf("%c", &a1[i]);
	} while (a1[i++] != '\n');
	a1[i - 1] = '\0';//此时a[i-1]为'\n',字符串有效内容到a[i-1]之前便结束了,故给a[i-1]赋值'\0'
	i = 0;      
	do {        //接收第二个字符串,并添加字符串结束标志'\0',避免后面计算长度时因没有'\0'出错
		scanf("%c", &a2[i]);
	} while (a2[i++] != '\n');
	a2[i - 1] = '\0';
	i = 0;
	do {        //接收第三个字符串,并添加字符串结束标志'\0',避免后面计算长度时因没有'\0'出错
		scanf("%c", &b1[i]);
	} while (b1[i++] != '\n');
	b1[i - 1] = '\0';
	i = 0;
	do {        //接收第四个字符串,并添加字符串结束标志'\0',避免后面计算长度时因没有'\0'出错
		scanf("%c", &b2[i]);
	} while (b2[i++] != '\n');
	b2[i - 1] = '\0';

2.计算四个字符串的长度,后面用于循环条件控制循环次数;

	a1_length = (int)strlen(a1);//计算字符串长度并保存
	a2_length = (int)strlen(a2);
	b1_length = (int)strlen(b1);
	b2_length = (int)strlen(b2);

3.设置循环,对四个字符串按两个一组,对他们进行比对。第一个字符串要找到两对相同的字符。为避免混乱,使用变量flag进行区分。flag为0,时,寻找第一对符合条件的字符,找到后按规则进行相应的处理;flag为1时,寻找第二对符合条件的字符,找到后按规则进行相应的处理,并结束第一组字符串的检测。

	for (i = 0; (i < a1_length) && (i < a2_length); i++)//控制字符串遍历不会超出数组界限
	{
		if ((a1[i] >= 'A') && (a1[i] <= 'G') && (a1[i] == a2[i]) && (flag == 0))
		{//若第一、二字符串的第i个元素为符合条件的大写字母且相等,且flag为0(说明在找第一对符合条件的字符)
			switch (a1[i]-'A'+1)//则根据解密规则输出相应的星期数和空格
			{
			case 1:{printf("MON ");break;}
			case 2:{printf("TUE ");break;}
			case 3:{printf("WED ");break;}
			case 4:{printf("THU ");break;}
			case 5:{printf("FRI ");break;}
			case 6:{printf("SAT ");break;}
			case 7:{printf("SUN ");break;}
			}
			flag++;//flag置1,结束第一组字符的查找
		}
		else if((a1[i]==a2[i])&&(flag==1))
		{
			if ((a1[i] >= '0') && (a1[i] <= '9'))//找到第二对符合条件的字符
			{
				printf("0%d:",a1[i]-'0');//输出是几时,并结束比对第一、二个字符串的循环
				break;
			}
			else if ((a1[i] >= 'A') && (a1[i] <= 'N'))
			{
				printf("%d:",a1[i]-'A'+10);
				break;
			}
		}
	}

4.对于第二组字符串,也是一样的,对各自的次序进行比对,符合条件的按规则进行相应的处理。

	for (i = 0; (i < b1_length) && (i < b2_length); i++)
	{//找到第3、4个字符串中符合条件的那一对字符
		if ((b1[i] == b2[i]) && ((b1[i] >= 'a' && b1[i] <= 'z') || (b1[i] >= 'A' && b1[i] <= 'Z')))
		{
			if (i <= 9)	printf("0%d", i);//输出现在是几分
			else		printf("%d", i);
			break;
		}
	}

四、全部代码

#include <stdio.h>
#include <string.h>
int main()
{
	char a1[61], a2[61], b1[61], b2[61];//a1,a2储存前两组字符串;b1,b2储存后两组字符串
	int i = 0;//循环变量,用于对字符串进行一一比对
	int flag = 0;//旗帜变量,用于指示正在第一组字符串中寻找第几对符合条件的字符
	int a1_length, a2_length, b1_length, b2_length;//保存四个字符串的长度
	do {        //接收第一个字符串,并添加字符串结束标志'\0',避免后面计算长度时因没有'\0'出错
		scanf("%c", &a1[i]);
	} while (a1[i++] != '\n');
	a1[i - 1] = '\0';//此时a[i-1]为'\n',字符串有效内容到a[i-1]之前便结束了,故给a[i-1]赋值'\0'
	i = 0;      
	do {        //接收第二个字符串,并添加字符串结束标志'\0',避免后面计算长度时因没有'\0'出错
		scanf("%c", &a2[i]);
	} while (a2[i++] != '\n');
	a2[i - 1] = '\0';
	i = 0;
	do {        //接收第三个字符串,并添加字符串结束标志'\0',避免后面计算长度时因没有'\0'出错
		scanf("%c", &b1[i]);
	} while (b1[i++] != '\n');
	b1[i - 1] = '\0';
	i = 0;
	do {        //接收第四个字符串,并添加字符串结束标志'\0',避免后面计算长度时因没有'\0'出错
		scanf("%c", &b2[i]);
	} while (b2[i++] != '\n');
	b2[i - 1] = '\0';
	a1_length = (int)strlen(a1);//计算字符串长度并保存
	a2_length = (int)strlen(a2);
	b1_length = (int)strlen(b1);
	b2_length = (int)strlen(b2);
	for (i = 0; (i < a1_length) && (i < a2_length); i++)//控制字符串遍历不会超出数组界限
	{
		if ((a1[i] >= 'A') && (a1[i] <= 'G') && (a1[i] == a2[i]) && (flag == 0))
		{//若第一、二字符串的第i个元素为符合条件的大写字母且相等,且flag为0(说明在找第一对符合条件的字符)
			switch (a1[i]-'A'+1)//则根据解密规则输出相应的星期数和空格
			{
			case 1:{printf("MON ");break;}
			case 2:{printf("TUE ");break;}
			case 3:{printf("WED ");break;}
			case 4:{printf("THU ");break;}
			case 5:{printf("FRI ");break;}
			case 6:{printf("SAT ");break;}
			case 7:{printf("SUN ");break;}
			}
			flag++;//flag置1,结束第一组字符的查找
		}
		else if((a1[i]==a2[i])&&(flag==1))
		{
			if ((a1[i] >= '0') && (a1[i] <= '9'))//找到第二对符合条件的字符
			{
				printf("0%d:",a1[i]-'0');//输出是几时,并结束比对第一、二个字符串的循环
				break;
			}
			else if ((a1[i] >= 'A') && (a1[i] <= 'N'))
			{
				printf("%d:",a1[i]-'A'+10);
				break;
			}
		}
	}
	for (i = 0; (i < b1_length) && (i < b2_length); i++)
	{//找到第3、4个字符串中符合条件的那一对字符
		if ((b1[i] == b2[i]) && ((b1[i] >= 'a' && b1[i] <= 'z') || (b1[i] >= 'A' && b1[i] <= 'Z')))
		{
			if (i <= 9)	printf("0%d", i);//输出现在是几分
			else		printf("%d", i);
			break;
		}
	}
	return 0;
}

五、优化代码
之前写这道题的时候被解密规则搞得有点晕,写接收字符串代码的时候,为了在字符数组中给字符串的内容补一个字符串结束标志’\0’,把字符串接收写得很复杂。其实只需要给每个接收字符串的字符数组赋初值’\0’,后面的所有元素都会自动补’\0’,然后直接用scanf函数接收字符串,字符串内容的后面自然就是’\0’了。

#include <stdio.h>
#include <string.h>
int main()
{
	char a1[61] = {'\0'}, a2[61] = { '\0' }, b1[61] = { '\0' }, b2[61] = { '\0' };//a1,a2储存前两组字符串;b1,b2储存后两组字符串
	int i = 0;//循环变量,用于对字符串进行一一比对
	int flag = 0;//旗帜变量,用于指示正在第一组字符串中寻找第几对符合条件的字符
	int a1_length, a2_length, b1_length, b2_length;//保存四个字符串的长度
	scanf("%s%s%s%s", a1, a2, b1, b2);
	a1_length = (int)strlen(a1);//计算字符串长度并保存
	a2_length = (int)strlen(a2);
	b1_length = (int)strlen(b1);
	b2_length = (int)strlen(b2);
	for (i = 0; (i < a1_length) && (i < a2_length); i++)//控制字符串遍历不会超出数组界限
	{
		if ((a1[i] >= 'A') && (a1[i] <= 'G') && (a1[i] == a2[i]) && (flag == 0))
		{//若第一、二字符串的第i个元素为符合条件的大写字母且相等,且flag为0(说明在找第一对符合条件的字符)
			switch (a1[i]-'A'+1)//则根据解密规则输出相应的星期数和空格
			{
			case 1:{printf("MON ");break;}
			case 2:{printf("TUE ");break;}
			case 3:{printf("WED ");break;}
			case 4:{printf("THU ");break;}
			case 5:{printf("FRI ");break;}
			case 6:{printf("SAT ");break;}
			case 7:{printf("SUN ");break;}
			}
			flag++;//flag置1,结束第一组字符的查找
		}
		else if((a1[i]==a2[i])&&(flag==1))
		{
			if ((a1[i] >= '0') && (a1[i] <= '9'))//找到第二对符合条件的字符
			{
				printf("0%d:",a1[i]-'0');//输出是几时,并结束比对第一、二个字符串的循环
				break;
			}
			else if ((a1[i] >= 'A') && (a1[i] <= 'N'))
			{
				printf("%d:",a1[i]-'A'+10);
				break;
			}
		}
	}
	for (i = 0; (i < b1_length) && (i < b2_length); i++)
	{//找到第3、4个字符串中符合条件的那一对字符
		if ((b1[i] == b2[i]) && ((b1[i] >= 'a' && b1[i] <= 'z') || (b1[i] >= 'A' && b1[i] <= 'Z')))
		{
			if (i <= 9)	printf("0%d", i);//输出现在是几分
			else		printf("%d", i);
			break;
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值