动态规划:
通过将大问题拆分成独立的小问题,先解决小问题。转换成代码的思路:网格方法,每个单元格为一个小问题。
举例:背包问题。
背包有重量限制3kg,3件物品有价值、重量两个属性。问题:在限制重量内装价值最大的物品。
分析思路:
1. 全排列组合。所有的物品组合为个,为[{},{A},{B},{C},{AB},{AC},{BC},{ABC}]。如果将所有组合的重量列出,运行时间,物品数量多的时候,非常慢。
2. 动态规划。单元格cell[i,j]表示对应限制条件i,j下的最大价值,各限制条件已经列出在表格中。最后一格cell[ItemC,3kg]内的最大价值,即为背包问题的最终答案。
cell[i,j] | 1kg | 2kg | 3kg |
Item A | 仅A可选,容量限制为1kg | 仅A可选,容量限制为2kg | 仅A可选,容量限制为3kg |
Item B | AB可选,容量限制为1kg | AB可选,容量限制为2kg | AB可选,容量限制为3kg |
Item C | ABC可选,容量限制为1kg | ABC可选,容量限制为2kg | ABC可选,容量限制为3kg |
填充完上述表格中的值后,可以归纳得到以下的计算公式:
根据上述公式就可以编写迭代的代码。
字符串比较问题也可以应用动态规矩,拆分成单个字母之间的比较。
最长公共子串:
比较两个字符串都包含的最长子串的长度。本例中的'vesista'和'hsis',拥有的最长公共子串为'sis'。
代码逻辑:利用dict生成一个7*4的表格cell,cell[1][2]表示截止到‘vi’和‘his’的最长公共子串。cell单元格内值的判断规律为:如果对应行列代表的两个字母相同,值为左上角邻居的值加1;如果两个字母不同,值为0。
# 最长公共子串 python3
word_a = "vesista"
word_b = "hsis"
def sim_count(word_a,word_b):
cell = [ [ 0 for x in range(len(word_b)) ] for y in range(len(word_a)) ] #初始化网格,全部赋值0
for i in range(len(word_a)):
for j in range(len(word_b)):
if word_a[i] == word_b[j] and (i < 1 or j < 1):
cell[i][j] = 1 #判断第一格的值
elif word_a[i] == word_b[j]:
cell[i][j]=cell[i-1][j-1]+1 #根据第一格累加
sim_atline = max(cell)
sim_last_word = max(sim_atline)
sim_last_word_i = cell.index(sim_atline)
for i in range(sim_last_word_i-sim_last_word+1,sim_last_word_i+1):
print(word_a[i],end=",")
return(cell,sim_last_word)
mat,sim_len = sim_count(word_a,word_b)
print(sim_len)
>> s,i,s,3
最长公共子序列:
按照最长公共子串的判断标准,如果比较'fish'和'fosh','fort'和'fosh',结果都是2,但明显'fosh'和'fish'更相近。这时候需要放宽连续子串的条件,变为公共子序列,即为两个字符串中共有的序列包含的字母数量之和。'fish'和'fosh'的最长公共子序列为3('f','sh'),而'fort'和'fosh'的结果是2。
代码逻辑:如果对应行列代表的两个字母相同,值为左上角邻居的值加1(与最长公共子串相同);如果两个字母不同,选择上方和左方邻居中较大的那个。利用dict生成表格,利于后面定位输出字符串。
# 最长公共子序列 python3
word_a = "fish"
word_b = "fosh" #最长公共子串为2,子序列为3
def sub_count(word_a,word_b):
cell = {}
for i in range(len(word_a)):
cell[i]={}
for j in range(len(word_b)):
cell[i][j]=0 #初始化网格,全部赋值0
if i < 1 or j < 1: #判断第一行,第一列的值
if word_a[i] == word_b[j]:
if i==0 and j==0:
cell[i][j] = 1
print(word_a[i],end=",")
elif i == 0 and j>=1:
cell[0][j] = cell[0][j-1]+1
print(word_a[i],end=",")
else:
cell[i][0] = cell[i-1][0]+1
print(word_a[i],end=",")
else:
if i==0 and j==0:
cell[i][j] = 0
elif i == 0 and j>=1:
cell[0][j] = cell[0][j-1]
else:
cell[i][0] = cell[i-1][0]
else: #根据第一行、第一列累加
if word_a[i] == word_b[j]:
cell[i][j]=cell[i-1][j-1]+1
print(word_a[i],end=",")
else:
cell[i][j]=max(cell[i-1][j],cell[i][j-1])
sim_len = []
for i in cell.values():
for j in i.values():
sim_len.append(j)
return(cell,max(sim_len))
mat,sim_len = sub_count(word_a,word_b)
print(sim_len)
>> f,s,h,3
参考资料:算法图解