Algorithm 字符串中需要更改的最小字符数的算法

Algorithm 字符串中需要更改的最小字符数的算法,algorithm,dynamic-programming,Algorithm,Dynamic Programming,几天前我遇到了一个编程挑战,现在已经结束了。问题是给定一个小写英文字母的字符串S,找出字符串S中需要更改的最小字符数,使其包含给定单词W作为S中的子字符串 同样在下一行中,按升序打印需要更改的字符位置。由于可以有多个输出,请查找第一个要更改的字符的最小位置 我尝试使用LCS,但只能得到需要更改的字符数。如何找到角色的位置? 我可能遗漏了什么,请帮忙。可能是其他算法来解决此问题。LCS(=最长公共子序列)将不起作用,因为W和S中的公共字母需要有匹配的位置。 因为您只允许更新,不允许删除/插入 如果

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

同样在下一行中,按升序打印需要更改的字符位置。由于可以有多个输出,请查找第一个要更改的字符的最小位置

我尝试使用LCS,但只能得到需要更改的字符数。如何找到角色的位置? 我可能遗漏了什么,请帮忙。可能是其他算法来解决此问题。

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

如果允许您删除/插入,则可以使用Levenshtein距离:

在您的例子中,一个明显的强力解决方案是在每个位置将W与S匹配,复杂性为O(N*M)(S的N个大小,W的M个大小)

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

如果允许您删除/插入,则可以使用Levenshtein距离:


在您的例子中,一个明显的强力解决方案是在每个位置将W与S匹配,复杂性为O(N*M)(S的N个大小,W的M个大小)

一个明显的解决方案是在输入字符串
S
上移动参考词
W
,并计算差异。但是,对于很长的字符串,这将变得效率低下。那么,我们如何改进这一点呢

我们的想法是将搜索目标定位在
S
中我们很可能与
W
匹配的地方。找到这些点是关键。如果不执行naive算法,我们无法高效准确地找到它们。因此,我们使用启发式
H
,它给出了我们必须执行的更改数量的下限。我们计算
S
的每个位置的下限。然后,我们从最低的
H
位置开始,检查该位置
S
W
的实际差异。如果下一个较高的
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++
我们可以看到,绝对差值之和的一半是我们需要更改的字母数的适当下限(因为每个字母的更改都会使总和减少2)。在这种情况下,界限甚至很紧,因为总和等于实际成本。然而,我们的启发式不考虑字母的顺序。但最终,这就是它可以有效计算的原因

好的,我们的启发式是直方图的绝对差值之和。现在,我们怎样才能有效地计算这个呢?幸运的是,我们可以增量计算直方图和总和。我们从位置0开始,计算完整直方图和绝对差值之和(请注意,
W
的直方图在剩余的运行时间内永远不会改变)。有了这些信息,我们可以设置
H(0)

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


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

显而易见的解决方案是将参考词
W
移到输入字符串
S
上,并计算差异。但是,对于很长的字符串,这将变得效率低下。那么,我们如何改进这一点呢

我们的想法是将搜索目标定位在
S
中我们很可能与
W
匹配的地方。找到这些点是关键。如果不执行naive算法,我们无法高效准确地找到它们。因此,我们使用启发式
H
,它给出了我们必须执行的更改数量的下限。我们计算
S
的每个位置的下限。然后,我们从最低的
H
位置开始,检查该位置
S
W
的实际差异。如果下一个较高的
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++
我们可以看到,绝对差值之和的一半是我们需要更改的字母数的适当下限(因为每个字母的更改都会使总和减少2)。在这种情况下,界限甚至很紧,因为总和等于实际成本。然而,我们的启发式不考虑字母的顺序。但最终,这就是它可以有效计算的原因

好的,我们的启发式是直方图的绝对差值之和。现在,我们怎样才能有效地计算这个呢?幸运的是,我们可以增量计算直方图和总和。我们从posit开始