利用python測試圓周率是否包含所有6位數(shù)密碼赫编,及其首次出現(xiàn)的位數(shù)
先使用y-cruncher生成圓周率的前2500萬位,數(shù)據(jù)保存在txt文件中,文件大小24MB垒拢,修改文件只保留小數(shù)點后的數(shù)字,接下來就可以對數(shù)據(jù)進行測試火惊。
1求类,最直接的辦法查找
index()函數(shù)可返回開始的索引值,即首次出現(xiàn)的位數(shù)屹耐,代碼如下:
pi_file = r'E:\測試\Pi-25000000.txt' # 讀取文件
with open(pi_file, 'r') as f:
pi = f.read()
#print(len(pi))
password_dict = {} # 字典保存尸疆,密碼-首次出現(xiàn)位數(shù)
for num in range(1000000): # 所有6位數(shù)字密碼
key = ('%06d' % num)
password_dict[key] = pi.index(key)
if num % 100000 == 0: # 查看進度
print(key)
save_file = r'E:\測試\Pi-password.txt' # 保存路徑
with open(save_file, 'w') as f:
for key, value in password_dict.items():
f.write('%s:%s\n' % (key, value))
測試結(jié)果:
000000-999999一共100萬種密碼都在圓周率前2500萬位中出現(xiàn),最后出現(xiàn)的密碼是569540惶岭,位數(shù)14118306(從0開始計數(shù))
不過代碼運行比較慢寿弱,圓周率2500萬位查找100萬種密碼,共耗時1059秒俗他。
2脖捻,改進代碼分段查找
這是由于不斷使用index()函數(shù)對2500萬位數(shù)字從左向右查找,重復(fù)查找過多兆衅,因此可以從數(shù)字中查找密碼地沮,這樣每6位數(shù)字只需查找一次,改進代碼如下:
pi_file = r'E:\測試\Pi-25000000.txt' # 讀取文件
with open(pi_file, 'r') as f:
pi = f.read()
password_dict = {} # 字典保存羡亩,密碼-首次出現(xiàn)位數(shù)摩疑,初始位數(shù)設(shè)為-1
for num in range(1000000): # 所有6位數(shù)字密碼
password_dict['%06d' % num] = -1
k = 100*10000 # 分段查找,每段設(shè)置位數(shù)
n_max = len(pi) // k # 防止死循環(huán)畏铆,最好整除
n = 1
while -1 in password_dict.values() and n <= n_max:
for i in range((n-1)*k, n*k):
password = pi[i:i+6]
if password_dict[password] == -1:
password_dict[password] = i
elif i < password_dict[password]:
password_dict[password] = i
n = n + 1
save_file = r'E:\測試\Pi-password.txt' # 保存路徑
with open(save_file, 'w') as f:
for key, value in password_dict.items():
f.write('%s:%s\n' % (key, value))
測試結(jié)果是一樣的雷袋,不過運行速度大幅提高,改進代碼僅耗時8.5秒辞居,相差120倍楷怒。
3,測試是否包含日期
既然6位數(shù)密碼都在圓周率的前2500萬位中瓦灶,那么接下來測試一下1921年至2020年所有日期是否也在其中鸠删。
按照慣例,先用最直接的辦法查找贼陶,不過index()函數(shù)未找到會報錯刃泡,改為find()函數(shù)查找巧娱,代碼如下:
pi_file = r'E:\測試\Pi-25000000.txt' # 讀取文件
with open(pi_file, 'r') as f:
pi = f.read()
birthday_dict = {} # 生日字典
mmdd = []
for m in range(1, 13):
for d in range(1, 32):
mmdd.append('%02d%02d' % (m, d))
temp = ['0229', '0230', '0231', '0431', '0631', '0931', '1131']
for i in temp:
mmdd.remove(i)
# 直接查找
for year in range(1921, 2021):
for md in mmdd:
yyyymmdd = str(year) + md
birthday_dict[yyyymmdd] = pi.find(yyyymmdd)
if (year % 4) == 0:
yyyymmdd = str(year) + '0229'
birthday_dict[yyyymmdd] = pi.find(yyyymmdd)
print(year)
save_file = r'E:\測試\Pi-birthday.txt' # 保存路徑
with open(save_file, 'w') as f:
for key, value in birthday_dict.items():
f.write('%s:%s\n' % (key, value))
測試結(jié)果:
1921年至2020年一共36525天只有8020天在圓周率前2500萬位中出現(xiàn),最先出現(xiàn)的日期是20190914烘贴,位數(shù)243禁添,最后出現(xiàn)的日期是19660505,位數(shù)24999789(從0開始計數(shù))
直接查找自然很慢桨踪,耗時731秒老翘,按照之前的方法進行改進,改進代碼如下:
# 分段查找
for year in range(1921, 2021):
for md in mmdd:
birthday_dict[str(year) + md] = -1
if (year % 4) == 0:
birthday_dict[str(year) + '0229'] = -1
k = 100*10000
n_max = len(pi) // k # 防止死循環(huán)馒闷,最好整除
n = 1
while -1 in birthday_dict.values() and n <= n_max:
for i in range((n-1)*k, n*k):
birthday = pi[i:i+8]
if birthday in birthday_dict: # 判斷是否為待查找日期
if birthday_dict[birthday] == -1:
birthday_dict[birthday] = i
elif i < birthday_dict[birthday]:
birthday_dict[birthday] = i
n = n + 1
改進代碼僅耗時4.3秒酪捡,相差170倍。
既然2500萬位沒有測試出所有日期出現(xiàn)的位數(shù)纳账,那么再試試看1億位逛薇,結(jié)果一共36525天有23163天出現(xiàn)了,最后出現(xiàn)的日期是19640421疏虫,位數(shù)99995337(從0開始計數(shù))