1

给定两个位字符串 x 和 y,其中 x 比 y 长,我想计算它们之间的 Levensthein 距离的一种不对称变体。从 x 开始,我想知道将 x 变为 y 所需的最小删除和替换次数。

我可以为此使用通常的 Levensthein 距离,还是我需要以某种方式修改算法?换句话说,对于通常的删除、替换和添加编辑,删除两个字符串之间的长度差异然后再添加一些位是否有益?我怀疑答案是否定的,但我不确定。如果我错了,我确实需要修改 Levenshtein 距离的定义以禁止删除,我该怎么做?

最后,如果我从 y (较短的字符串)开始并且只允许添加和替换,我会直觉地期望我会得到相同的距离。这是正确的吗?我对这些答案有所了解,但我无法证明它们。

4

1 回答 1

2

如果我理解正确,我认为答案是肯定的,Levenshtein 编辑距离可能与只允许删除和替换更大字符串的算法不同。因此,您需要修改或创建不同的算法来获得您的受限版本。

考虑两个字符串“ABCD”和“ACDEF”。Levenshtein 距离为 3 (ABCD->ACD->ACDE->ACDEF)。如果我们从较长的字符串开始,并将自己限制为删除和替换,我们必须使用 4 次编辑(1 次删除和 3 次替换。原因是对较小字符串应用删除以有效获取较大字符串的字符串不能从较长的字符串开始时可以实现,因为它没有免费的插入操作(因为您不允许这样做)。

你的最后一段是真的。如果从较短到较长的路径只使用插入和替换,那么任何允许的路径都可以简单地从较长到较短的反转。无论方向如何,替换都是相同的,但是从小到大的插入在反转时变成了删除。

我还没有彻底测试过,但这个修改显示了我将采取的方向,并且似乎与我测试过的值一起工作。它是用 c# 编写的,并遵循 wikipedia 条目中关于 Levenshtein 距离的伪代码。可以进行明显的优化,但我没有这样做,因此我对标准算法所做的更改更加明显。一个重要的观察是(使用您的约束)如果字符串的长度相同,那么替换是唯一允许的操作。

    static int LevenshteinDistance(string s, string t) {
        int i, j;
        int m = s.Length;
        int n = t.Length;

        // for all i and j, d[i,j] will hold the Levenshtein distance between
        // the first i characters of s and the first j characters of t;
        // note that d has (m+1)*(n+1) values
        var d = new int[m + 1, n + 1];

        // set each element to zero
        // c# creates array already initialized to zero

        // source prefixes can be transformed into empty string by
        // dropping all characters
        for (i = 0; i <= m; i++) d[i, 0] = i;

        // target prefixes can be reached from empty source prefix
        // by inserting every character
        for (j = 0; j <= n; j++) d[0, j] = j;

        for (j = 1; j <= n; j++) {
            for (i = 1; i <= m; i++) {
                if (s[i - 1] == t[j - 1])
                    d[i, j] = d[i - 1, j - 1];       // no operation required
                else {
                    int del = d[i - 1, j] + 1;   // a deletion
                    int ins = d[i, j - 1] + 1;   // an insertion
                    int sub = d[i - 1, j - 1] + 1; // a substitution
                    // the next two lines are the modification I've made
                    //int insDel = (i < j) ? ins : del;
                    //d[i, j] = (i == j) ? sub : Math.Min(insDel, sub);
                    // the following 8 lines are a clearer version of the above 2 lines 
                    if (i == j) {
                        d[i, j] = sub;
                    } else {
                        int insDel;
                        if (i < j) insDel = ins; else insDel = del;
                        // assign the smaller of insDel or sub
                        d[i, j] = Math.Min(insDel, sub);
                    }
                }
            }
        }
        return d[m, n];
    }
于 2014-11-30T00:26:25.713 回答