字符串S中需要更改的最少字符数的算法

时间:2018-08-28 06:39:03

标签: algorithm dynamic-programming

几天前,我遇到了编程挑战,现在已经结束了。这个问题说,给定一个小写英文字母的字符串S,找到需要在字符串S中更改的最少字符数,以便它在S中包含给定的单词W作为子字符串。

也在下一行中,以升序打印需要更改的字符的位置。由于可以有多个输出,因此找到第一个字符更改最少的位置。

我尝试使用LCS,但只能获取需要更改的字符数。如何找到角色的位置? 我可能缺少一些东西,请帮忙。可能还有其他算法可以解决它。

2 个答案:

答案 0 :(得分:2)

显而易见的解决方案是将参考词W移到输入字符串S上并计算差值。但是,这对于很长的字符串将变得无效。那么,我们该如何改善呢?

这个想法是将搜索目标定位在S很有可能与W匹配的地方。找到这些斑点是关键部分。如果不执行朴素算法,我们将无法高效,准确地找到它们。因此,我们使用一种启发式H,它为我们必须执行的更改数量提供了一个下限。我们为S的每个位置计算此下限。然后,我们从最低H的位置开始,并检查该位置SW的实际差异。如果下一个更高的H高于当前差异,则我们已经完成。如果不是,我们检查下一个位置。该算法的概述如下:

input:
    W of length LW
    S of length LS

H := list of length LS - LW + 1 with tuples [index, mincost]
for i from 0 to LS - LW
    H(i) = [i, calculate Heuristic for S[i .. i + LW]]
order H by mincost
actualcost = infinity
nextEntryInH = 0
while actualcost >= H[nextEntryInH].minCost && nextEntryInH < length(H)
    calculate actual cost for S[H[nextEntryInH].index .. + LW]
    update actualcost if we found a lesser cost or equal cost with an earlier difference
    nextEntryInH++

现在,回到启发式方法。我们需要找到一些东西,使我们能够近似给定位置的差异(并且我们需要保证它是一个下限),同时又易于计算。由于我们的字母是有限的,因此我们可以使用字母的直方图来执行此操作。因此,让我们以注释为例:W = worldcup,而我们感兴趣的S部分是worstcap。这两个部分的直方图是(省略不出现的字母):

         a c d l o p r s t u w
worldcup 0 1 1 1 1 1 1 0 0 1 1  
worstcap 1 1 0 0 1 1 1 1 1 0 1 
------------------------------
abs diff 1 0 1 1 0 0 0 1 1 1 0  (sum = 6)

我们可以看到,绝对差之和的一半是我们需要更改的字母数的适当下限(因为每个字母的更改都会使和减少2)。在这种情况下,由于总和等于实际成本,因此边界甚至很紧。但是,我们的启发式方法不考虑字母顺序。但是最后,这就是使它可以有效计算的原因。

好吧,我们的启发式方法是直方图的绝对差之和。现在,我们如何有效地计算呢?幸运的是,我们可以逐步计算直方图和总和。我们从位置0开始,计算完整的直方图和绝对差之和(请注意,W的直方图在整个运行时的其余部分将永远不会改变)。有了这些信息,我们就可以设置H(0)

要计算H的其余部分,请在S上滑动窗口。当我们将窗口向右滑动一个字母时,我们只需要更新直方图并稍微求和即可:窗口中正好有一个新字母(添加到直方图中),一个字母离开窗口(从直方图中删除) 。对于两个(或一个)对应的字母,计算绝对差之和的结果变化并对其进行更新。然后,相应地设置H

使用这种方法,我们可以计算整个字符串S在线性时间内的启发式。启发式方法为我们指明了在哪里寻找匹配项。一旦有了它,我们将继续执行此答案开头概述的其余算法(在启发式较低的地方开始准确的成本计算,并继续进行,直到实际成本超过下一个更高的启发式值为止。)

答案 1 :(得分:0)

LCS(=最长公共子序列)将不起作用,因为W和S中的公共字母需要具有匹配的位置。 由于只允许您进行更新,而不能删除/插入。

如果允许您删除/插入,则可以使用Levenshtein距离: https://en.wikipedia.org/wiki/Levenshtein_distance

在您的情况下,一个明显的蛮力解决方案是在每个位置将W与S匹配,复杂度为O(N * M)(S的N大小,W的M大小)