Python与世界完全对称日--爱与狗粮的竞争

背景:

本来是老老实实的看论文,准备搞毕设,突然发现今天是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个) :点击查看

展望:

代码是搞完了啊,我寻思要不要去民政局门口蹲一下,万一哪个小姐姐眼瞎看上我了,那今天岂不是双喜临门呀,多好的日子啊。可惜一想到这该死的疫情就脑壳疼,那帮子吃蝙蝠的二货是怎么想的,请问你们是想倒挂在树上洗头呢,还是想在天上飞呢?神农老祖当年也就敢尝尝百草呢,呵呵,你们倒是比他还牛逼啊,人生本就短暂,你们还要去走捷径啊?

啊啊啊,爱情仿佛就这样离我而去,悲伤辣麽大!

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值