一、题目
原题链接: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 个。