zoukankan      html  css  js  c++  java
  • 杨辉三角+优化算法

     1 # 杨慧三角基本实现方式
     2 # triangle = [[1],[1, 1]] # 将所有的结果放在一个大列表中
     3  
     4 # for i in range(2, 6): # 因为已经有两个了,索引从 2 开始 
     5 #     pre = triangle[i - 1] # 上一个大列表中的 元素
     6 #     cur = [1]           # 当前大列表中的 元素,定义新的元素,并且首位补1
     7 #     for j in range(i - 1): # 对上一个大列表中的元素循环计算,得到当前列表中的 元素(通过循环得到循环次数)
     8 #         cur.append(pre[j] + pre[j + 1]) # 上一个元素中前一项 + 后一项,就是当前元素
     9 #     cur.append(1) # 尾部补 1
    10 #     triangle.append(cur)
    11 # print(triangle)
    12 
    13 # 变体:
    14 
    15 # triangle = [[1]] # 将所有的结果放在一个大列表中
    16  
    17 # for i in range(1, 6): # 因为已经有两个了,索引从 2 开始 
    18 #     pre = triangle[i - 1] # 上一个大列表中的 元素
    19 #     cur = [1]           # 当前大列表中的 元素,定义新的元素,并且首位补1
    20 #     for j in range(i - 1): # 对上一个大列表中的元素循环计算,得到当前列表中的 元素(通过循环得到循环次数)
    21 #         cur.append(pre[j] + pre[j + 1]) # 上一个元素中前一项 + 后一项,就是当前元素
    22 #     cur.append(1) # 尾部补 1
    23 #     triangle.append(cur)
    24 # print(triangle)
    25 
    26 # 再变体
    27 # triangle = [] # 将所有的结果放在一个大列表中
    28  
    29 # for i in range(6): # 因为已经有两个了,索引从 2 开始     
    30 #     cur = [1]  # 当前大列表中的 元素,定义新的元素,并且首位补1  
    31 #     triangle.append(cur)
    32 #     if i == 0: continue
    33 #     pre = triangle[i-1]    
    34 #     for j in range(i - 1): # 对上一个大列表中的元素循环计算,得到当前列表中的 元素(通过循环得到循环次数)
    35 #         cur.append(pre[j] + pre[j + 1]) # 上一个元素中前一项 + 后一项,就是当前元素
    36 #     if i > 0:
    37 #         cur.append(1) # 尾部补 1
    38     
    39 # print(triangle)
     1 # 补零法 
     2 # # NO 1 只补一个:右侧补零
     3 # 1 0    
     4 # 1 1 0   # 上一位的最后一项 即-1 位置 + 0 位置
     5 # 1 2 1 0
     6 # 1 3 3 1 0
     7 # triangle = [[1],[1, 1]] 
     8  
     9 # for i in range(2, 5): 
    10 #     pre = triangle[i - 1] + [0] # 注 ,这里不能用append() ,因为返回None
    11 #     cur = []           
    12 #     for j in range(i + 1): # 当i = 2 时,测试得需要循环 3 次,所以 i + 1
    13 #         cur.append(pre[j - 1] + pre[j]) # j = 0 ,pre[-1] + pre[0]   j = 1 ,pre[0] + pre[1]
    14 #     triangle.append(cur)
    15 # print(triangle)
    16 
    17 
    18 # triangle = [[1]] 
    19 # for i in range(1, 5): 
    20 #     pre = triangle[i - 1].copy() # 浅拷贝
    21 #     pre.append(0) # 补零
    22 #     cur = []  # 如果不需要之前的结果,这里用cur.clear() ,否则内存空间产生很多的垃圾。         
    23     
    24 #     for j in range(i + 1): # 等价  while offset <= i
    25 #         cur.append(pre[j - 1] + pre[j])   # cur.append(pre[offset - 1] + pre[offset]) 
    26 #     triangle.append(cur)
    27 # print(triangle)
    28 
    29 
    30 
    31 # -------------------------------------------------------------------------------------
    32 
    33 
    34 # # NO 2 两侧补零
    35 # 0 1 0    
    36 # 0 1 1 0   # 上一位  位置0 + 位置 1
    37 # 0 1 2 1 0
    38 # 0 1 3 3 1 0
    39 
    40 # triangle = [[1],[1, 1]]  
    41 # for i in range(2, 5): 
    42 #     pre = [0] + triangle[i - 1] + [0] # [0,1,1,0]
    43 #     cur = []           
    44 #     for j in range(i + 1):# i = 2  , 0.1
    45 #         cur.append(pre[j]+ pre[j+1])    #j = 0 pre[0]+pre[1, j = 1 pre[1] + pre[2]
    46 #     triangle.append(cur)
    47 # print(triangle)
    48 
    49 
    50 # # 变形
    51 # triangle = [[1]]  
    52 # for i in range(1, 5): 
    53 #     pre = [0] + triangle[i - 1] + [0] # [0,1,1,0]
    54 #     cur = []           
    55 #     for j in range(i + 1):# i = 2  , 0.1
    56 #         cur.append(pre[j]+ pre[j+1])    #j = 0 pre[0]+pre[1, j = 1 pre[1] + pre[2]
    57 #     triangle.append(cur)
    58 # print(triangle)
    59 
    60 # # 再变形
    61 # triangle = [] 
    62 # for i in range(5): 
    63 #     if i == 0:
    64 #         cur = [1]
    65 #         triangle.append(cur)
    66 #         continue
    67 #     pre = [0] + triangle[i - 1] + [0]
    68 #     cur = []           
    69 #     for j in range(i + 1):
    70 #         cur.append(pre[j]+ pre[j+1])    
    71 #     triangle.append(cur)
    72 # print(triangle)
     1 # 对称法:
     2 # 1               
     3 # 1 1             
     4 # 1 2  1            i = 2   计算 1 次   2//2    奇数行 中间的数  j=1 i=2 i=2j
     5 # 1 3  3 1          i = 3        1      3//2    
     6 # 1 4  6 4 1        i = 4        2      4//2    奇数行 中间的数  j=2 i=4  i=2j
     7 # 1 5 10 10 5 1     i = 5        2      5//2    
     8 # 把所有行都保存了,这样往后越来越占空间
     9 # n = 4
    10 # triangle = [[1],[1,1]]
    11 
    12 # for i in range(2,8):# 2    3 4
    13 # #     cur = [1]
    14 # #     for j in range(i):
    15 # #         cur.append(1 if j == i-1 else 0)     
    16 #     cur = [1] * (i + 1) # i = 2,cur=[1,1,1]  i=3 cur=[1,1,1,1]  i=4 cur=[1,1,1,1,1] 
    17 #     pre = triangle[i - 1] # pre=[1,1]   pre=[1,2,1] pre [1,3,3,1]
    18     
    19 #     for j in range(i // 2):  # j = 0   j= 0 j=0,1
    20 #         val = pre[j] + pre[j + 1]  # pre[0]+pre[1] 4  pre[1]+pre[2] 6
    21 #         cur[j + 1] = val # 覆盖第二项
    22 # #       if i != 2 * j:  # 跳过 i = 2*j 的一项
    23 #         cur[-j - 2] = val # cur[-2]=2   cur[-3] = 6  覆盖之前的值           
    24 #     triangle.append(cur)
    25 # print(triangle)
    26 
    27 # i = 2  1 2 1      0,1,2
    28 # i = 3  1 3 3 1    0.1.2.3  j=[0]  后面 -1
    29 # I = 4  1 4 6 4 1   j=[0,1]  后面 -2  -1   -j-1
    30 
    31 
    32 
    33 
    34 
    35 # 优化:降低空间复杂度(单行覆盖)
    36 
    37 # 单行覆盖法
    38 # n = 5
    39 # row = [1] * n
    40 
    41 # for i in range(n):
    42 #     offset = n - i # 比如n = 4,i = 3,n-i 就是去除左侧用不到的
    43 #     z = 1
    44 #     for j in range(i//2):# i=2,j=0  # i=3,j=0      
    45 #         val = z + row[j + 1]  # val=1+row[1] # val=1+row[1]=3
    46         
    47 #         # 记录上一该位置的值,比如 i = 3时,如果不记录,会被val覆盖
    48 #         # 此时计算下一个,3 = 3 + 1而不是 2 + 1
    49 #         z = row[j + 1] # z=row[1] # z=row[1]=2
    50                         
    51 #         row[j + 1] = val # row[1]=2 #row[1]=2
    52 #         if i != 2 * j:# 2!=0 # 3!=0
    53 #             row[-j - 1 - offset] = val # row[-4]=2 # row[-3]=3 
    54         
    55 #     print(row[:i + 1])
    56     
    57 
    58 # 1    1 1 1 1 
    59 # 1 1    1 1 1  ---- 1 2 1 1 1  ---  
    60 # 1 2 1    1 1
    61 # 1 3 3 1    1
     1 '''
     2 求杨辉三角某一个的某个值
     3     思路1:使用之前的办法,将三角求出来,在找某行的某个值
     4     思路2: 利用数学公式,即是组合数的值(二项式展开式的系数,(a + b)** n)
     5 
     6 '''
     7 # NO:1  
     8 # 两行来处理 ,这是又一种求杨慧三角的算法,通过两行相互交替
     9 # m = 6
    10 # k = 2
    11 
    12 # oldline = []
    13 # for i in range(m): 
    14 #     newline = [1] * (i + 1)# 3 [1,1,1]  [1,1] 
    15     
    16 #     if i < 2: 
    17 #         oldline = newline
    18 #         continue
    19     
    20 #     for j in range(i - 1): # 0,1
    21 #         newline[j + 1] = oldline[j] + oldline[j + 1]
    22 #     oldline = newline
    23 # print(newline)
    24 # print(newline[k-1])
    25 
    26 # 优化:
    27 # m = 6
    28 # k = 2
    29 
    30 # oldline = []
    31 # for i in range(m): 
    32 #     newline = [1] * (i + 1)
    33 #     for j in range(i - 1): 
    34 #         newline[j + 1] = oldline[j] + oldline[j + 1]
    35 #     oldline = newline
    36 # print(newline)
    37 # print(newline[k-1])
    38 
    39 
    40 
    41 # NO.2
    42 # 利用组合公式 C(n,m) = n!/(m!*(n-m)!)
    43 # m = 6
    44 # k = 2
    45 
    46 # n = m - 1 # 这块可以不写,主要分析用
    47 # r = k - 1
    48 # d = m - k
    49 
    50 # f = 1
    51 # offset = [] # 用来放三个结果
    52 
    53 # for i in range(1, n + 1): # 每一行都是从第一个数 1 开始
    54 #     f *= i  
    55 #      因为分子部分肯定包含了分子,所以算到分子的时候记录下来,知道算到分子大小的阶乘位置
    56 #     if i == (m - k):
    57 #         offset.append(f)
    58 #     if i == (k - 1):
    59 #         offset.append(f)
    60 #     if i ==(m - 1):
    61 #         offset.append(f)
    62 # print(int(offset[2]/(offset[1] * offset[0])))

    总结:

    基本实现方式的编程思想:
    1、对于杨慧三角,前两行比较特殊,先把前两行提取出来。
    2、利用大列表,将所有的数据放在该列表中。
    3、利用列表的性质,控制上一行和当前行
    4、首尾补 1
    5、用到双层for循环,第一层控制行,第二层控制运算。
    6、对于规律性的问题,先测试前几行,测试通过后,在测试后续基本没有大问题,结构需要在调整一下。
    7、变体,即结构的调整,尽量将特殊行也加入到循环中,注意是否需要条件判断这些特殊行
    8、注意使用一些简化结构:if i == 0: continue
    补零法:
    1、分析杨慧三角,可以看出,上一行前后相加,,就是下一行的值,而首尾都是1,所以可以考虑首尾补零的方法。
    2、补零可以有两种,首尾都补,一侧补
    3、补零,注意虽然使用列表,但是注意列表返回值是否是None,还是新列表。
    4、这里使用了+ 或浅拷贝追加0 两种方式
    5、cur = [] 如果不需要之前的结果,这里用cur.clear() ,否则内存空间产生很多的垃圾。
    6、for j in range(i + 1):
    cur.append(pre[j - 1] + pre[j])
    # 等价 while offset <= i
    # cur.append(pre[offset - 1] + pre[offset])

    对称法 and 单行覆盖法:
    1、 对结果分析可以看出,只需要计算左侧的即可,所以考虑使用对称法
    2、这里用到的主要思想是:
    - 直接开辟一定的空间,上面的方法,每次都把之前的保存下来,按照需求,不需要,所以直接操作同一个列表即可
    - 开辟一定大小的空间,对于杨慧三角来说,通过结果规律发现,首尾都是1,中间其他数字,所以可以开辟这样的空间:首尾为1,其他位为0.或者最好的方式是都为1,产生新的数值,覆盖原有的数字即可。
    # # cur = [1]
    # # for j in range(i):
    # # cur.append(1 if j == i-1 else 0)
    or
    # # cur = [1] * (i + 1) # i = 2,cur=[1,1,1] 
    3、计算时,只计算左侧一般,而且有奇数行,会有一个中间数,此时 i = 2j, 因为要对称,所以算完前半部分,在跳过这个值(先判断不等于后),在利用列表索引赋值。
    4、注意点:对单行运算,前一次的运算结果,会覆盖原来位置的值,所以需要一个临时变量接受这个值,以便下次计算使用。

    注:要时刻注意内存的使用,当内存被占用到一定的阈值,就会出道GC 对内存清理,此时程序会暂停,降低了运行效率,所以根据具体情况使用列表,是一次性给,还是用一次删一次。

    为什么要坚持,想一想当初!
  • 相关阅读:
    重磅!容器集群监控利器 阿里云Prometheus 正式免费公测
    阿里开源 KT Connnect,轻量级云原生测试环境治理平台来啦!
    使用Velero Restic快速完成云原生应用迁移至ACK集群
    Kubernetes 弹性伸缩全场景解析 (一):概念延伸与组件布局
    北京DAY1下午
    洛谷 P3041 [USACO12JAN] Video Game Combos
    Tyvj 1729 文艺平衡树
    bzoj 3238: [AHOI2013]差异
    bzoj 2957: 楼房重建
    bzoj 2660: [Beijing wc2012]最多的方案
  • 原文地址:https://www.cnblogs.com/JerryZao/p/9450673.html
Copyright © 2011-2022 走看看