蓝桥杯:回文日期

一、题目

        原题链接:https://www.lanqiao.cn/problems/498/learning/

        题目描述:2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202,恰好是一个回文数。我们称这样的日期是回文日期。

        有人表示 20200202 是 “千年一遇” 的特殊日子。对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。

        也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。对此小明也不认同,因为大约 100 年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 2121 年 12 月 12 日。算不上 “千年一遇”,顶多算 “千年两遇”。

        给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。

        输入描述

        输入包含一个八位整数 NN,表示日期。

        对于所有评测用例,10000101 <= N <= 89991231,保证 N 是一个合法日期的 8 位数表示。

        输出描述

        输出两行,每行 1 个八位数。第一行表示下一个回文日期,第二行表示下一个 ABABBABA 型的回文日期。

二、解题思路

 1. 提炼需求:

        (1)输入N,10000101 <= N <= 89991231

        (2)N 是一个合法日期, N是 8 位数

        (3)下一个回文日期

        (4)下一个ABABBABA型回文日期

2. 自顶向下理顺思路

        怎么寻找下一个回文日期呢?最笨的方法就是一个一个日期地试,换言之叫“遍历”。这对于人来说,很难做到;但对于计算机来说很简单。很多解题,当你想明白遍历,就简单了。这里通过日期不断加1,直到找到下一个回文日期为止,来实现编程。

        为了清晰好理解,判断是否合法拟作函数,单独编程。后续有需要也会增加其他函数。

int main() {
    输入n;
    判断n的范围是否正确;
    判断n是否合法日期;
    
    // 求回文日期
    日期加1;
    判断新日期是否合法;
    合法则判断是否回文;
    判断是否ABABBABA型;
    判断下一个日期,直到找到;

    输出日期;
    return 0;
}

三、 代码实现

#include <iostream>
using namespace std;
bool isLegal(int date);
bool leapYear(int year);
void split(int date, int* sp_date);
int main()
{
	// date
	int date;
	cin >> date;
	// detect the range of date
	if (date < 10000101 || date > 89991232) { // make sure the date has 8 numbers.
		cout << "please input date between 10000101 and 89991231 " << endl;
		exit(0);
	}
	if (!isLegal(date)) {
		cout << "the date is illegal" << endl;
		exit(0);
	}
	
	// find the next date
	date++;
	// store the numbers of the date one by one
	int* pdate = new int[8];
	int nextDate, nextABAB_Date;
	bool getNext, getABAB;  // whether get the next number
	getNext = false;
	getABAB = false;
	while (!getNext || !getABAB) { // when not get the next and not get the next ABAB, cicular
		// detect the legality of date
		if (isLegal(date)) {
			split(date, pdate);
			for (int i = 0; i < 4; i++) {
				// 判断对应的回文位置数字是否相同
				if (pdate[i] == pdate[7 - i]) {
					// 如果当前是第四个数字
					if (3 == i) {
						if (!getNext) {
							nextDate = date;
						    getNext = true;
						}
						if (!getABAB) {
							if (pdate[0] == pdate[2] && pdate[1] == pdate[3]) {
								nextABAB_Date = date;
								getABAB = true;
							}
						}
					}
					continue;
				}	
				else 
					break;
			}
			date++;
		}
		else {
			date++;
			continue;
		}
	}
	
	cout << nextDate << endl;
	cout << nextABAB_Date << endl;
	
	return 0;
}

/*
 * to judge the date whether is legal or not
 * and to split the date, then get 8 numbers stored in pointer named date
 */
bool isLegal(int date) {
	// default: the date is illegal, that is false
	bool legal = false;

	// get the year, the month, and the day
	int year, month, day;
	year = date / 10000;
	date = date - year * 10000;
	month = date / 100;
	day = date - month * 100;
	
	// judge the month whether it is legal or not
	if (month > 12 || month == 0) {
		legal = false;
		return legal;
	}
	// the maximum of the day in a month
	int maxDay;
	switch (month) {
	case 1 :
	case 3 :
	case 5 :
	case 7 :
	case 8 :
	case 10 :
	case 12 :
		maxDay = 31;
		break;
	case 4 :
	case 6 :
	case 9 :
	case 11:
		maxDay = 30;
		break;
	case 2 :
		if (leapYear(year))
			maxDay = 29;
		else
			maxDay = 28;
		break;
	}
	// judge the day whether it is legal or not
	if (day > maxDay || day == 0) {
		legal = false;
	}
	else
		legal = true;

	return legal;
}

/*
 * to judge the year whether is leap year
 * return: true means yes, and false means no
 */
bool leapYear(int year) {
	if (year % 4 == 0 && year % 100 != 0)
		return true;
	else if (year % 400 == 0)
		return true;
	else
		return false;
}

void split(int date, int* sp_date) {
	// get the year, the month, and the day
	int year, month, day;
	year = date / 10000;
	date = date - year * 10000;
	month = date / 100;
	day = date - month * 100;

	// split the numbers
	sp_date[0] = year / 1000;
	year = year - sp_date[0] * 1000;
	sp_date[1] = year / 100;
	year = year - sp_date[1] * 100;
	sp_date[2] = year / 10;
	sp_date[3] = year - sp_date[2] * 10;

	sp_date[4] = month / 10;
	sp_date[5] = month - sp_date[4] * 10;

	sp_date[6] = day / 10;
	sp_date[7] = day - sp_date[6] * 10;

	//return *sp_date;
}

四、调试阶段

1. 计算逻辑出错

        day = date - date * 100;

    错误,应该是

        day = date - month * 100;

2. 迭代自增缺失,导致死循环

        通过while循环判断date是否回文,在while循环中是一个if...else...语句,else语句让迭代量date++,但是if条件中忘记将date++,使得算法出错,得不到答案。

        解决:在if代码体末添加迭代自增。

3. 判断闰年

        有两种。

        一是能被四整除,但不能被100整除。则为闰年。

        二是能被400整除。则为闰年。

4. 回文判断

        共8个数,只需判断四次数字是否相同。当数字是第 i 个时(i从0开始),则对应判断的数字应该是第 7-i 个。

五、运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值