fibonacci数列
-
黄金分割数列/兔子数列(因以兔子繁殖为例子引入)
-
假设一对兔子(一雄一雌)出生后第三个月开始繁殖,每个月都可以生一对兔子,而新生的兔子出生后第三个月也开始繁殖。问n个月后,有多少对兔子?
斐波那契通过推理得到了以下递归关系:
f(0) = 0 f(1) = 1 f(n) = f(n-1) + f(n-2) (n≥2)
其中,f(n)表示第n个月的兔子对数。
-
-
从第三项开始,每一项都是前两项的和
- F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)
- 是线性递推数列
代码实现
- 递归实现:
def Fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return Fibonacci(n - 1) + Fibonacci(n - 2)
- 迭代实现:
def FasterFibonacci(n):
F = [0, 1]
for i in range(2, n + 1):
F.append(F[i - 1] + F[i - 2])
return F[n]
递归有着大量的重复运算,使用迭代运算会节省许多时间。
- 对比递归与迭代的时间:
start = time.time()
Fibonacci(30) # 因为n大时递归太慢了,所以用小n递归和大n迭代也能比较
end = time.time()
print('n=30递归:'+ str(end - start))
start = time.time()
FasterFibonacci(1000)
end = time.time()
print('n=1000迭代:'+ str(end - start))
# 输出结果:
# n=30递归:0.4313187599182129
# n=1000迭代:0.0005943775177001953
最长公共子序列LCS
参考:动态规划 最长公共子序列 过程图解_Running07的博客-CSDN博客
子序列sequenceVS子串substring
子序列可不连续,子串则必须连续
求出LCS
图中的空白格子c[i,j]的定义:记录的LCS的长度值
- 横竖(i,j)对应的两个元素相等,该格子的值 = c[i-1,j-1] + 1
- 如果不等,取c[i-1,j] 和 c[i,j-1]的最大值
S1的元素3=S2的元素3,所以 c[2,1] = c[1,0] + 1
S1的元素3 != S2的元素5,c[2,2] =max(c[1,2],c[2,1]),取图中两个黄色的最大值
依次填写直到最后一行
依图构造LCS——溯源:
- +1得来的:(作特殊标记)溯源——左上角元素
- 非+1所得的:从其左方or上方的元素溯源
eg:
c[8][9] = 5,且S1[8] != S2[9],所以倒推回去,c[8][9]的值来源于c[8][8]的值(因为c[8][8] > c[7][9])。
c[8][8] = 5, 且S1[8] = S2[8], 所以倒推回去,c[8][8]的值来源于 c[7][7]。
如图所示:
即LCS ={3,5,7,7,8}或{3,4,6,7,8}
代码实现
# 从后往前溯源,每个相等的元素入栈,找到一个完整的LCS后依次出栈
# 此时可找到不同的LCS
stack = []
# 答案用集合存储,因为集合本身不可重复,可去重
ans = set()
# LCS:最长公共子序列
def LCS(X, Y, i, j, flag):
if flag[i][j] == 0:
# print(stack)
# 因为入栈顺序从后到前,因此变为字符串时需倒序
s = ''.join(stack[len(stack) - 1 - i] for i in range(len(stack)))
ans.add(s)
return
if flag[i][j] == 'p':
stack.append(X[i - 1])
LCS(X, Y, i - 1, j - 1, flag)
stack.pop(-1)
elif flag[i][j] == 'l':
LCS(X, Y, i, j - 1, flag)
elif flag[i][j] == 'u':
LCS(X, Y, i - 1, j, flag)
else:
LCS(X, Y, i - 1, j, flag)
LCS(X, Y, i, j - 1, flag)
return ans
# length为上面所画的表格
# flag表示该长度溯源
def LCSlength(X, Y):
lenth = [[0 for col in range(len(X) + 1)] for row in range(len(Y) + 1)]
flag = [[0 for col in range(len(X) + 1)] for row in range(len(Y) + 1)]
for i in range(len(X)):
for j in range(len(Y)):
if X[i] == Y[j]:
lenth[i + 1][j + 1] = lenth[i][j] + 1
flag[i + 1][j + 1] = 'p' # plus,即溯源左上角
elif lenth[i + 1][j] > lenth[i][j + 1]:
lenth[i + 1][j + 1] = lenth[i + 1][j]
flag[i + 1][j + 1] = 'l' # left,即溯源左侧元素
elif lenth[i + 1][j] < lenth[i][j + 1]:
lenth[i + 1][j + 1] = lenth[i][j + 1]
flag[i + 1][j + 1] = 'u' # up,即溯源右侧元素
else:
lenth[i + 1][j + 1] = lenth[i][j + 1]
flag[i + 1][j + 1] = 'b' # both,左上皆可,可通过不同路径找到不同的LCS
if lenth[i + 1][j + 1] == 0: flag[i + 1][j + 1] = 0
return flag
测试:
X = 'ACCGGTC'
Y = 'GTCGTTC'
X = list(X)
Y = list(Y)
flag = LCSlength(X, Y)
print(LCS(X, Y, len(X), len(Y), flag))
# 输出结果:
# {'GGTC', 'CGTC'}
表格表示: