1. 最长公共子串
最长公共子串与最长公共子序列有一些类似,只不过这里子串要求是连续的。
这里我们定义 lcs[i][j] 表示以 s[i] 与 t[j] 为末尾元素的最长公共子串长度,那么我们有:
import numpy as np
s = 'mitcmu'
t = 'mtacmu'
def longest_commom_substr(s, t):
m = len(s)
n = len(t)
lcs = np.zeros((m, n), 'uint8')
max_lcs = 0
for i in range(0, n):
if s[0] == t[i]:
lcs[0][i] = 1
else:
lcs[0][i] = 0
for i in range(0, m):
if s[i] == t[0]:
lcs[i][0] = 1
else:
lcs[i][0] = 0
for i in range(1, m):
for j in range(1, n):
if s[i] == t[j]:
lcs[i][j] = lcs[i-1][j-1] + 1
max_lcs = max(max_lcs, lcs[i][j])
else:
lcs[i][j] = 0
print(lcs)
return max_lcs
print(longest_commom_substr(s, t))
2. 矩阵链乘法
假设有一系列矩阵 $
由于矩阵乘法满足结合律,所以有:
按照这几种顺序计算需要的代价是不一样的。比如:
![3f48af4a86ea284fe909966c803fa236.png](https://img-blog.csdnimg.cn/img_convert/3f48af4a86ea284fe909966c803fa236.png)
我们定义状态
$$state[i][j] = begin{cases} 0 &text{如果 }i == j min_{ileqslant k< j}(state[i][k]+state[k+1][j]+p_{i-1}p_{k}p_{j}) &text{如果 } i也就是我们把
计算的时候,我们则需要自底向上地更新状态变量,最后逐渐得到问题的解。
![0562bf238f2145d64fc500216efca2b1.png](https://img-blog.csdnimg.cn/img_convert/0562bf238f2145d64fc500216efca2b1.png)
算法伪代码如下所示:
![4d16be1eced697e40952fbc5289b7c9c.png](https://img-blog.csdnimg.cn/img_convert/4d16be1eced697e40952fbc5289b7c9c.png)
import numpy as np
max_num = 2 ** 31 - 1
p = [(10, 100), (100, 5), (5, 50)]
p = [(30, 35), (35, 15), (15, 5), (5, 10), (10, 20), (20, 25)]
def matrix_chain_order(p):
n = len(p)
state = max_num * np.ones((n, n), 'int32')
divide = np.zeros((n, n), 'uint8')
for i in range(n):
state[i][i] = 0
for s in range(1, n):
for i in range(n-s):
j = i + s
for k in range(i, j):
temp = state[i, k] + state[k+1, j] + p[i][0] * p[k][1] * p[j][1]
if temp < state[i][j]:
state[i][j] = temp
divide[i, j] = k
print(state)
print(divide)
return state[0, n-1]
print(matrix_chain_order(p))
上述代码中有 6 个矩阵,运行结果如下,第一个输出为状态矩阵,第二个输出为划分矩阵,最终需要的计算次数为
![a6772caffd7bf59fb25c682119948332.png](https://img-blog.csdnimg.cn/img_convert/a6772caffd7bf59fb25c682119948332.png)
由