您将获得一个字符串,并且最多可以更改字符串中的Q个字母。您还会获得一个子字符串列表(每两个字符长),并带有相应的分数。字符串中每个子字符串的出现都会增加您的总分。可达到的最大分数是多少?
字符串长度< = 150,Q< = 100,子串数< = 700
示例:
String = bpdcg
Q = 2
子串:
bz - 得分:2
zd - 得分:5
dm - 得分:7
ng - 得分:10
在这个例子中,你可以达到最大分数b改变" p"在字符串中的一个" z"和" c"到了" n"。因此,你的新字符串是" bzdng"得分为2 + 5 + 10 = 17。
我知道给定一个已经改变了字母的字符串,可以使用字典匹配算法(例如aho-corasick(或稍微复杂一点,Rabin Karp))以线性时间检查分数。但是,尝试每两个字母替换将花费太长时间,然后检查将花费太长时间。
我认为另一种可能的方法是向后工作,从给定的子串构造理想的字符串,然后检查它是否与原始字符串最多相差两个字符。但是,我不知道如何做到这一点,即使可以做到,我认为这也需要很长时间。
最好的方法是什么?
答案 0 :(得分:1)
解决此问题的有效方法是使用动态编程。
设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})
有一些优化空间:
总的来说,如果评分词中有不同的字母,则算法在时间O(QN * k ^ 2)中运行。通过上面的第二个优化,这可以减少到O(QNw),其中w是得分词的数量。