更改字符串的字母以获得最高分数

时间:2014-10-28 02:37:35

标签: string algorithm search string-hashing

  

您将获得一个字符串,并且最多可以更改字符串中的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))以线性时间检查分数。但是,尝试每两个字母替换将花费太长时间,然后检查将花费太长时间。

我认为另一种可能的方法是向后工作,从给定的子串构造理想的字符串,然后检查它是否与原始字符串最多相差两个字符。但是,我不知道如何做到这一点,即使可以做到,我认为这也需要很长时间。

最好的方法是什么?

1 个答案:

答案 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})

有一些优化空间:

  • 如果j变为负数
  • ,计算不会提前终止
  • 当给出选择时,会尝试L2的每个值,而只有可以完成d得分词的字母需要尝试。

总的来说,如果评分词中有不同的字母,则算法在时间O(QN * k ^ 2)中运行。通过上面的第二个优化,这可以减少到O(QNw),其中w是得分词的数量。