用python解小学数学题——小议算法效率

暑假某天,小孩跑来问我一道数学题如下(小学题):
现在奶奶的年龄是小明的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…

原创文章!未经许可,禁止转载!

你可能感兴趣的:(python3学习笔记)