解决这个问题的一种有效方法是使用动态规划。
令 L 是开始任何长度为 2 的评分子串的字母集,以及一个特殊字母“*”,它代表除这些之外的任何其他字母。
令 S(i, j, c) 是使用 j 替换的字符串(直到索引 i)中可能的最大分数,其中字符串以字符 c 结尾(其中 c 在 L 中)。
递归关系有点混乱(或者至少,我没有找到特别漂亮的公式),但这里有一些代码可以计算出可能的最大分数:
infinity = 100000000
def S1(L1, L2, s, i, j, c, scores, cache):
key = (i, j, c)
if key not in cache:
if i == 0:
if c != '*' and s[0] != c:
v = 0 if j >= 1 else -infinity
else:
v = 0 if j >= 0 else -infinity
else:
v = -infinity
for d in L1:
for c2 in [c] if c != '*' else L2 + s[i]:
jdiff = 1 if s[i] != c2 else 0
score = S1(L1, L2, s, i-1, j-jdiff, d, scores, cache)
score += scores.get(d+c2 , 0)
v = max(v, score)
cache[key] = v
return cache[key]
def S(s, Q, scores):
L1 = ''.join(sorted(set(w[0] for w in scores))) + '*'
L2 = ''.join(sorted(set(w[1] for w in scores)))
return S1(L1, L2, s + '.', len(s), Q, '.', scores, {})
print S('bpdcg', 2, {'bz': 2, 'zd': 5, 'dm': 7, 'ng': 10})
有一些优化空间:
- 如果 j 为负,则计算不会提前终止
- 当给定一个选择时,L2 的每个值都被尝试,而只有可以完成来自 d 的评分词的字母才需要尝试。
总体而言,如果评分词中有 k 个不同的字母,则算法运行时间为 O(QN*k^2)。通过上面的第二个优化,这可以减少到 O(QNw),其中 w 是评分词的数量。