背景:
本来是老老实实的看论文,准备搞毕设,突然发现今天是2020.0202,谐音“爱你爱你,你爱你爱”。不得不说,这么有爱的“对称日”还是第一次碰见,上网一搜,果不其然,连民政局都在实力宠新人呢。嗯,今天是个不错的日子,适合结婚,要不要直接跟女朋友表白去拿证?突然,一阵敲门声响起...等等,女朋友?总所周知,程序员这种生物岂会有女朋友???大家退后啊,别滋了 别滋了,诶诶,那个尿毒症的快走,我还年轻不想死...现在醒了,刚刚喝多了,抱歉抱歉。即使是这个对单身狗充满恶意的日子,我也不能忘记自己的本职----敲代码,那么问题来了,总共有多少这种对称日呢?网上只看到js版本的,太旧了不想看,那就必须动动我机智的小脑瓜了。Python 3.6 走起~~~~
时间段:1000.01.01~9999.12.31(一万年太久,只争朝夕,哈哈哈哈)
边学边敲,所以先上几个Demo...
# Test Demo
dateC = datetime.datetime(1971, 1, 1)
dateTuple = dateC.timetuple()
# print(dateTuple)
# 日期到时间戳的转换
timestamp = time.mktime(dateTuple)
# print(timestamp)
# 时间戳转换到日期
timeStr = time.strftime("%Y%m%d", dateTuple)
# print(timeStr)
初想法:
不想动脑筋就直接暴力遍历走起,类似回文数嘛...
import datetime
import time
def is_symmetric(date):
datestr = time.strftime("%Y%m%d", date.timetuple())
revestr = ''.join(reversed(datestr))
return datestr == revestr
dateNow = datetime.datetime(1000, 1, 1) # 初始化起始日
year = 1000
n = 1 # 一次增加的天数
dateList = [] # 列表存放对称日
count = 0 # 用于统计对称日个数
print("程序处理中...")
startTimeStamp = time.time() # 程序起始时间
while year <= 9998:
if is_symmetric(dateNow):
dateList.append(dateNow) # 加入列表
count = count + 1
# print(dateNow.strftime("%Y-%m-%d")) # 这里设置输出格式
dateNow = dateNow + datetime.timedelta(days=n) # 往后推n=1天
year = dateNow.year
endTimeStamp = time.time() # 程序终止时间
print("已处理完成...")
print("程序运行总计耗时{:.5f}秒。".format(endTimeStamp-startTimeStamp))
print("该时间段内总计{0}个对称日。".format(count))
# 格式化输出dateList
newLine = 0
for date in dateList:
print(date.strftime("%Y-%m-%d"), end=" ")
newLine = newLine + 1
if newLine % 8 == 0: # 一行输出8个
print("")
newLine = 0
可以看到总共331个对称日, 运行结果截图(部分)如下,运行时间就按14秒算吧:
新想法:
注意到可以根据月份,日期的范围对年份进行限制,这样可以大大减少判断的天数...,我们把年份拆成两部分,前两位与Day比较(变量命名:part1_year),后两位与Month比较(变量命名:part2_year)
- 天数对年份的限制(day在[1,31]),推出part1_year在[1,92],其实是包含31个元素的集合
- 月份对年数的限制(month在[1,12]),推出part2_year在集合{10,20,30,40,50,60,70,80,90,01,11,21}内
关于此,可以写一个函数get_part_year_list(tuple)来提前获取这些集合
而因为此处我对年份时间段作了限制范围,故暂不考虑年份反过来对month和day的约束...话不多说,代码呈上:
import datetime
import time
def is_symmetric(date):
datestr = time.strftime("%Y%m%d", date.timetuple())
revestr = ''.join(reversed(datestr))
return datestr == revestr
def get_part_year_list(tp):
result = []
for t in tp:
# 因为这里最多是两位数,所以可以直接逆序
m = t // 10 # 此处需要注意若为/则是浮点型
nn = t % 10
result.append(nn * 10 + m)
return result
# 提前求出两个集合
month_list = get_part_year_list(range(1, 13))
day_list = get_part_year_list(range(1, 32))
# print(month_list)
# print(day_list)
dateNow = datetime.datetime(1000, 1, 1) # 初始化起始日
year = 1000
n = 1 # 一次增加的天数
dateList = [] # 列表存放对称日
count = 0 # 用于统计对称日个数
print("程序处理中...")
startTimeStamp = time.time() # 程序起始时间
while year <= 9998:
part1_year = year // 100
part2_year = year % 100
if part1_year in day_list and part2_year in month_list: # 年份受到约束
if is_symmetric(dateNow):
dateList.append(dateNow) # 加入列表
count = count + 1
# print(dateNow.strftime("%Y-%m-%d")) # 这里设置输出格式
dateNow = dateNow + datetime.timedelta(days=n) # 往后推n=1天
year = dateNow.year
endTimeStamp = time.time() # 程序终止时间
print("已处理完成...")
print("程序运行总计耗时{:.5f}秒。".format(endTimeStamp-startTimeStamp))
print("该时间段内总计{0}个对称日。".format(count))
# 格式化输出dateList
# ...
这不,运行时间变成了(4.6秒)接近三分之一...
当然,反过来,月份和日期也会被年份限制,应该还能加快速度,此处就没有往下写了(以后补充)...
继续优化:
注意到之前列表起到的巨大作用,由于年份的四位数已经被拆开,那么函数is_symmetric(date)的存在便显得有点突兀,换成另外一种判断方法:分布将part1_year与day,part2_year与mon比较即可,此处便将列表换为字典数据结构..代码如下:
import datetime
import time
def get_part_year_dict(tp):
result = {} # 这里修改成字典
for t in tp:
# 因为这里最多是两位数,所以可以直接逆序
m = t // 10 # 此处需要注意若为/则是浮点型
nn = t % 10
result[nn * 10 + m] = t # 键:倒序的数字 值:原数字
return result
# 提前求出两个集合
month_dict = get_part_year_dict(range(1, 13))
day_dict = get_part_year_dict(range(1, 32))
# print(month_dict)
# print(day_dict)
dateNow = datetime.datetime(1000, 1, 1) # 初始化起始日
year = 1000
n = 1 # 一次增加的天数
dateList = [] # 列表存放对称日
count = 0 # 用于统计对称日个数
print("程序处理中...")
startTimeStamp = time.time() # 程序起始时间
while year <= 9998:
part1_year = year // 100
part2_year = year % 100
if part1_year in day_dict.keys() and part2_year in month_dict.keys():
month = dateNow.month
day = dateNow.day
if month_dict[part2_year] == month and day_dict[part1_year] == day:
dateList.append(dateNow) # 加入列表
count = count + 1
# print(dateNow.strftime("%Y-%m-%d")) # 这里设置输出格式
dateNow = dateNow + datetime.timedelta(days=n) # 往后推n=1天
year = dateNow.year
endTimeStamp = time.time() # 程序终止时间
print("已处理完成...")
print("程序运行总计耗时{:.5f}秒。".format(endTimeStamp-startTimeStamp))
print("该时间段内总计{0}个对称日。".format(count))
# 格式化输出dateList
# ...
偌,结果如下,又少了1.6秒:
部分对称日(36个):
这些结果竖着往下看还是有些规律的...
2001-10-02 2010-01-02 2011-11-02 2020-02-02 2021-12-02 2030-03-02
2040-04-02 2050-05-02 2060-06-02 2070-07-02 2080-08-02 2090-09-02
2101-10-12 2110-01-12 2111-11-12 2120-02-12 2121-12-12 2130-03-12
2140-04-12 2150-05-12 2160-06-12 2170-07-12 2180-08-12 2190-09-12
2201-10-22 2210-01-22 2211-11-22 2220-02-22 2221-12-22 2230-03-22
2240-04-22 2250-05-22 2260-06-22 2270-07-22 2280-08-22 2290-09-22
所有对称日(331个) :点击查看
展望:
代码是搞完了啊,我寻思要不要去民政局门口蹲一下,万一哪个小姐姐眼瞎看上我了,那今天岂不是双喜临门呀,多好的日子啊。可惜一想到这该死的疫情就脑壳疼,那帮子吃蝙蝠的二货是怎么想的,请问你们是想倒挂在树上洗头呢,还是想在天上飞呢?神农老祖当年也就敢尝尝百草呢,呵呵,你们倒是比他还牛逼啊,人生本就短暂,你们还要去走捷径啊?
啊啊啊,爱情仿佛就这样离我而去,悲伤辣麽大!