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 對內存清理,此時程序會暫停,降低了運行效率,所以根據具體情況使用列表,是一次性給,還是用一次刪一次。