不对称的Levenshtein距离

时间:2014-11-29 23:17:32

标签: dynamic-programming levenshtein-distance edit-distance

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

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

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

1 个答案:

答案 0 :(得分:2)

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

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

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

我没有彻底测试过这个,但是这个修改显示了我将采取的方向,并且似乎与我用它测试过的值一起工作。它是用c#编写的,并遵循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];
    }