杨辉三角+优化算法

 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 对内存清理,此时程序会暂停,降低了运行效率,所以根据具体情况使用列表,是一次性给,还是用一次删一次。

posted @ 2018-08-09 18:02  JerryZao  阅读(1258)  评论(0编辑  收藏  举报