暑假某天,小孩跑来问我一道数学题如下(小学题):
现在奶奶的年龄是小明的6倍,若干年后,奶奶的年龄是小明的5倍,又若干年后,奶奶的年龄是小明的4倍。问现在小明和奶奶各多少岁。
一道凑数字的题目,想着要用多元方程解还得给小孩说怎么解多元方程。凑数字的方法也太LOW,直接写代码给解了算,顺便教码二代编程(已基本教会小孩python基本知识)。于是随手写下:
def method_1():
import time
age = range(1, 100) # 考虑题目应该是符合实际的定了这个年龄段
start = time.time()
for ming in age:
for grand in age:
for x in age:
for y in age:
if ming * 6 == grand and (ming+x) * 5 == (grand+x) and (ming+y) * 4 == (grand+y):
t = time.time() - start
print(t)
return ming, grand, x, y-x
果然一运行,BIU的一下(12,72,3,5)
小孩看了就验证了一下,嗯,没错!我小得意的说:这么简单的东西还能有错啊~他能看懂计算方法的,但不懂这个计算方法的复杂度是O(n^4)。
结果小孩问:这种题是不是应该有多个答案。我答:很显然有嘛,不过年龄比较符合实际情况的应该就这个。为了教育下一代,我随手添了个0把range(1,100)
改成了range(1,1000)
准备算几个不科学的答案告诉他。
? 结果悲刷了!电脑卡死…
还好我机灵:加上计算运行时间代码(粗算),又运行一次说:看到没有,这种多个嵌套循环要少用,它的计算复杂度是指数级的!这个程序就是4次方级的!我们只算100以内的数字就用了近0.6秒的计算时间!而且运算1000以内的数字就OVER了,所以我们要改改:
def method_2():
import time
age_list_1, age_list_2, age_list_3 = [], [], []
age = range(1, 1000)
start = time.time()
for ming in age:
for grand in age:
if ming*6 == grand:
age_list_1.append([ming, grand])
for i in range(len(age_list_1)):
for x in age:
if (age_list_1[i][0] + x) * 5 == (age_list_1[i][1] + x):
age_list_2.append([age_list_1[i][0], age_list_1[i][1]])
for j in range(len(age_list_2)):
for y in age:
if (age_list_2[j][0] + y) * 4 == (age_list_2[j][1] + y):
age_list_3.append([age_list_2[j][0], age_list_2[j][1]])
t = time.time() - start
print(t)
return age_list_3
我心想改成O(n^2) 应该足够运算到万级的数了!
BIU的一下,结果出来了:
0.11858749389648438
[[12, 72], [24, 144], [36, 216], [48, 288], [60, 360], [72, 432], [84, 504], [96, 576], [108, 648], [120, 720], [132, 792], [144, 864], [156, 936]]
说道:后面的数和前面的是倍数关系,很好理解吧,144年就有点不科学了,再往后就是不可能的了。所以12,72是正确答案!
没想到他还来劲了!问:那你现在这个能计算到多少岁。我答:万级吧。可以试试的(age = range(1, 10000)):
11.631418228149414
[[12, 72], [24, 144], [36, 216], [48, 288], [60, 360], [72, 432], [84, 504], [96, 576], [108, 648], [120, 720], [132, 792], [144, 864], [156, 936], [168, 1008], [180, 1080]......
用时11秒多。。。计算出了万以内的答案!暗暗庆幸说的是万,没说是十万!
小孩说你这电脑是不是太慢了点?答:是有些年头了,不过主要是计算方法的问题,我只是随便给你弄个答案出来!要是计算你小学生的数学题就要用上“神威·太湖之光”。又一通科普。。。
小孩回我说:那你再改进一下,让我看看科学点的计算方法!
还好,这个难不倒我,我改成O(n)总行了吧:
def method_3():
import time
age_list = [[12, 72]]
age = range(1, 1000000)
start = time.time()
for x in age:
if x > 1 and age_list[-1][-1] < age[-1]:
age_list.append([age_list[0][0]*x, age_list[0][1]*x])
x += 1
t = time.time() - start
print(t)
return age_list
看到没,只循环一次,百万级的数轻松完成!
0.2667992115020752
[[12, 72], [24, 144], [36, 216], [48, 288], [60, 360], [72, 432], [84, 504]......
又问我:千万行不?亿呢?
答:千万应该能计算,亿怕是不行了。
一通乱试,果然只能计算到千万级。
问:你是不是应该换个电脑了?连个小学生的题目都算不好的电脑要来干嘛!
答:胡说!看我再改一下,说了是计算方法问题!(为了省个电脑钱,我也不容易):
def method_4(n):
ming, grand = 12, 72
while int(n) >= 1:
yield ming*n, grand*n
n -= 1
哟~这回这么简单了?难道越简单运行越快?这个yield是什么功能?
又一通教学!用以下方法输出10万个答案:
a = method_4(100000)
for x in a:
print(x)
用a.__next__()
可以输出任意第几个答案。终于保住我的X240…