• 杨辉三角


    杨辉三角

    形如以下为杨辉三角

    杨辉三角有很多性质,我们用以下两种简单的性质来用python实现。

    1第n行的数字有n项。

    2每个数等于它上方两数之和.

    n=6
    trangle = [[1]]
    for i in range(1,n):
        pre=trangle[i-1]
        cur=[1]
        trangle.append(cur)
        for j in range(i-1):
            cur.append(pre[j]+pre[j+1])
        cur.append(1)
    print(trangle)
    列表实现

     这是最简单的一种方法,关键在于控制边界方法就是不断的代入测试,只要前两遍也就是第三行和第四行可以实现,后边就应当能够实现,第一二行可以先特殊对待,在程序实现后,在回头扩宽边界。

     除了以1为边界外,还可以在两侧补零

    n=6
    #######杨辉三角两侧补零
    l=[[1]]
    for i in range(1,n):
        pre=[0]+l[i-1]+[0]
        cur=[]
        l.append(cur)
        for j in range(i+1):
            cur.append(pre[j]+pre[j+1])
    print(l)
    两侧补零

    两侧补零在左侧补零会频繁调动列表移动,更好的办法是在右侧补零,最左边的索引为0的值为上一列的索引为-1和0的两项的和,也就是0+1刚好是1,需要注意的也是边界问题,如下

     1 ##杨辉三角右侧补零
     2 n=6
     3 l=[[1]]
     4 for i in range(1,n):
     5     pre=l[i-1]+[0]
     6     cur=[]
     7     l.append(cur)
     8     for j in range(i+1):
     9         cur.append(pre[j-1]+pre[j])
    10 print(l)
    杨辉三角右侧补零

    杨辉三角是一个轴对称图形,可以在计算时只计算左侧的数值,在数据量变大时,可以提高效率。

    这里使用先建立一个列表,n个1,n是要求到的行数。使用

    n=6
    l=[[1]]
    for i in range(1,n):
        p=l[i-1]
        c=[1]*(i+1)
        for j in range(0,i//2):
            value=p[j]+p[j+1]
            c[j+1]=value
            if i!=2j:
                c[-j-2]=value
        l.append(c)
    print(l)
    利用轴对称的性质

    使用两个列表相互循环

    %%timeit
    m=20
    k=7
    
    for i in range(m):
        newline=[1]*(i+1)
        e=i//2
        for j in range(e):
            newline[j+1]=oldline[j]+oldline[j+1]
            if j!=e:
                newline[-j-2]=newline[j+1]
        oldline=newline
        
    #print(newline)

    输出      30.2 µs ± 327 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

    使用一个列表实现

    这里使用先建立一个列表,n个1,n是要求到的行数。使用list[:3],表示取出从0到3的元素,循环取出打印,最后列表只保留最后的一行数据

    n=6
    lst=[1]*n
    for i in range(n):
        e=i//2
        tmp=1
        offset=n-i
        for j in range(1,e+1):
            value=tmp+lst[j]
            tmp=lst[j]
            lst[j]=value
            if i != 2j:
                lst[-j-offset]=value
        print(lst[:i+1])
    一个列表实现

     输出  23.1 µs ± 323 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

    使用一个列表或的思想是生产中,对于能知道范围的数据,提前建立足够用的列表,在后期的使用中足够用,能用替换就少用append,能不遍历就不遍历。

    使用一个列表减少了空间复杂度,但是时间复杂度并未减少,应当注意在列表值增大后,在每次列表更新后,原来的列表只是没有了引用计数,但并未消失,在内存中变成了内存垃圾。在技算量达到极高的量级时,每次产生的垃圾都会对内存造成冲击,如果此时,python的GC(垃圾处理)会停止其他一切内存活动,只进行垃圾处理,内存空间的整理,此时可能产生的问题是,内存没有足够的空间存放你的下一个列表,它会挪动你当前的列表,效率问题及大。

    解决方案是优化算法,将庞大的列表分成一个个小的部分进行处理。

    一旦数据量增大,要时刻注意效率问题。

    在内存中,一旦内存使用率到达一定阈值,会触发python的自动的垃圾回收,在对垃圾回收没有足够的了解时,不要手动垃圾回收,会对系统造成性能影响。

    通项公式的解法

    C(n-1,m-1)=(n-1)!/[(m-1)!(n-m)!]

    解法

    ####trangle.2
    while True:
        m = input('m=')
        if str.isdigit(m):
            m = int(m)
            k = input('k=')
            if str.isdigit(k):
                k = int(k)
                if k > m:
                    print('k<=m only')
                else:
                     break
            else:
                print('numbre only')
        else:
            print('numbre only')
    a = 1
    b = 1
    c = 1
    e = m - k
    for i in range(1,m):
        a *= i
        if i == k - 1:
            b = a
        if i == e:
            c = a
    print(int(a / (b * c)))

    取消上半部输入程序,输出为  2.25 µs ± 47.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

    使用相同的算法,将列表引入,如下

    %%timeit
    n=20
    lst=[1]*n
    for i in range(n):
        e=i//2
        tmp=1
        offset=n-i
        for j in range(1,e+1):
            value=tmp+lst[j]
            tmp=lst[j]
            lst[j]=value
            if i != 2j:
                lst[-j-offset]=value
       # print(lst[:i+1])

    输出  2.43 µs ± 36 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

    以上所用算法中,在单独求某一行,某一位时,使用通项公式速度较快,在使用列表时,调用了append函数,速度比直接赋值给标识符慢一点,可能原因是append函数导致的。

    在计算某一行或者打印杨辉三角时,耗时较接近,使用对称的性质时在相应方法内效率较高。

  • 相关阅读:
    [LeetCode] 67. 二进制求和
    [LeetCode] 66. 加一
    [LeetCode] 65. 有效数字
    [LeetCode] 63. 不同路径 II
    [LeetCode] 64. 最小路径和
    [LeetCode] 61. 旋转链表
    [LeetCode] 62. 不同路径
    [LeetCode] 59. 螺旋矩阵 II
    [LeetCode] 60. 第k个排列
    [LeetCode] 58. 最后一个单词的长度
  • 原文地址:https://www.cnblogs.com/rprp789/p/9449426.html
Copyright © 2020-2023  润新知