问题描述:
把年月日表示为 YYYYMMDD 这样的 8 位整数,然后把这个整数转换成 二进制数并且逆序排列,再把得到的二进制数转换成十进制数,求与原日期一 致的日期。求得的日期要在上一次东京奥运会(1964 年 10 月 10 日)到下一 次东京奥运会(预定举办日期为 2020 年 7 月 24 日)之间。
例)日期为1966年7月13日时 ① YYYYMMDD格式→
19660713
② 转换成二进制数→
1001010111111111110101001
③ 逆序排列→
1001010111111111110101001
④ 把逆序排列得到的二进制数转换成十进制数→
19660713
分析:
处理日期多麻烦哦,我们交给库函数处理,嘿嘿。剩下的我们需要考虑怎样优化算法。先看时间转化为二进制的范围
19641010
→
1001010111111111110101001
,
20200724
→
1001101000011110100010100
。可以看到二进制前4位是一样的,所以后面的四位也需要是
1001
。即我们所需要的十进制数字满足:
(dec - 9 )%16 == 0 -----(1)
,这里我们需要分两种情况考虑:
- 当前日期加上16时年月不变,这时我们可以直接用之前的日期十进制数加上16作为下个十进制数,而不需要再次转化。
-
当前日期加上16年或月变化,这时我们需要将当前的日期日期重置1,重新寻找满足等式
(1)
的十进制数字。
代码实现:
#include <time.h>
#include <vector>
using std::vector;
int toDec (const tm & cur_date);
void getNext (tm* cur_date);
void searchStart(int encoded, tm* start_date);
int main() {
struct tm start_date = {0};
vector <tm> res;
start_date.tm_mday = 1;start_date.tm_year = 70;start_date.tm_mon = 0;//mktime is available after 1970.
int encoded = toDec(start_date);
searchStart(encoded, &start_date);
while (encoded <= 20200724){
int p_end = 0x00000010, p_begin = 0x00100000;
while (p_end != p_begin){
if ((bool)(p_begin & encoded) == (bool)(p_end & encoded)){//detect one bit. remember transform to bool.
p_begin = p_begin >> 1;
p_end = p_end << 1;
}else{
break;
}
}
if (p_end == p_begin)
res.push_back(start_date);
getNext(&start_date);
encoded = toDec(start_date);
}
printf("palindromic date has been listed as follow \n");
for (const auto i : res){
printf("%s\n", asctime(&i));
}
return 0;
}
void getNext (tm* cur_date){
cur_date->tm_mday += 16;
int pre_mon = cur_date->tm_mon;
mktime(cur_date);
if (cur_date->tm_mon != pre_mon){
cur_date->tm_mday = 1;
searchStart(toDec(*cur_date), cur_date);
}//turn to next month.
}
int toDec (const struct tm & cur_date){
int encodeed = (cur_date.tm_year + 1900)*10000 + (cur_date.tm_mon + 1)*100
+ cur_date.tm_mday;//Be careful the rule of date.
return encodeed;
}
void searchStart(int encoded, tm* start_date){
const int p = 0x0000000f;
while((encoded & p) != 0x00000009) {
encoded++;
start_date->tm_mday++;
}
}
这里顺便总结一下头文件
time.h
的一些常用日期处理用法(具体参见
c++ reference
):
time_t mktime (struct tm * timeptr);//将创建的tm转换为time_t,time_t是time_ptr所指向的对象与19700101相差的秒数,该过程
与localtime正相反。且将日期转换为合理的格式,例如20190435会被更改为20190505。
struct tm * localtime (const time_t * timer);//将时间转换为本地时间
char* asctime (const struct tm * timeptr);//返回表示时间的字符串形如:Www Mmm dd hh:mm:ss yyyy
值得一提的是,C /C++用 32 位的二进制数来表示以 1970 年 1 月 1 日为起点的时间,这也是上述程序以1970为起点的原因所在,如果向
mktime
传递的时间小于1970年,则会得到-1,所以如果处理1970年以前的时间则需要另谋他法。