对于不完整的字符串,是否有任何修改的最小编辑距离(Levenshteina距离)?

时间:2012-04-21 11:36:19

标签: algorithm levenshtein-distance

我从0和1开始构建序列。我想以某种方式衡量他们与目标字符串的距离。但目标字符串不完整。

我拥有的数据示例,其中x是目标字符串,其中[0]表示至少有一个'0'

x =11[0]1111[0]1111111[0]1[0]`, the length of x is fixed and eaquel to length of y.

y1=11110111111000000101010110101010111

y2=01101000011100001101010101101010010
all y's have the same length

很容易看出x确实可以被解释为字符串集,但是这个集可能非常大,可能只是我需要从该集合中进行采样并取平均最小编辑距离,但同样是太大的计算问题。

我试图找出算法,但我已经堆叠了,它的步骤看起来像这样: x - 目标字符串 - 模糊一,

y - 第二个字符串 - 已修复 Cx1,Cy1 - x和y中的数字 Gx1,Gy1 - 向量列表,每个列表的长度等于给定序列中的一组的数量,

Gx1 [i] i-vector,

Gx1 [i] =(第i组中的第一组,第i组的长度)

如果Gx1和Gy1的长度相同,那么我们知道要从每个组中添加或删除多少个,但是有一个问题,因为我不知道简单的添加和删除是否给出最小距离

2 个答案:

答案 0 :(得分:1)

令(Q,Σ,δ,q 0 ,F)为目标自动机,它接受常规语言L⊆Σ * ,并让w∈Σ * 是源字符串。你想计算min x∈L d(x,w),其中d表示Levenshtein距离。

我的方法是概括通常的动态程序。设D是由Q×{0,...,| w |}索引的表。在计算结束时,D(q,i)将是

min x:δ(q 0 ,x)= q d(x,w [0 ... i]),

其中w [0 ... i]表示w的长度 - (i + 1)前缀。换句话说,D(q,i)是w [0 ... i]与使自动机处于状态q的字符串集之间的距离。总体答案是

min q∈F D(q,| w |),

或w与自动机处于最终状态之一的字符串集之间的距离,即语言L.


D的第一列由每个状态q∈Q的条目D(q,0)组成。因为对于每个字符串x∈Σ * ,它认为d(x,ε)= | x |,条目D(q,0)是由转移函数δ定义的图中从q 0 到q的最短路径的长度。通过从q 0 运行“Dijkstra算法”来计算这些条目(实际上只是广度优先搜索,因为边长都是1)。

D的后续列从前一列计算。首先通过最小化几种可能性来计算辅助量D'(q,i)。

完全匹配对于每个状态r∈Q使得δ(r,w [i])= q,包括D(r,i - 1)。

删除包括D(q,i - 1)+ 1。

替换对于每个状态r∈Q和每个字母a∈Σ∖{w [i]}使得δ(r,a)= q,包括D(r,i-1) + 1。

请注意,我遗漏了插入。与第一列一样,这是因为可能需要在此处插入许多字母。为了从D'(i,q)s计算D(i,q)s,在具有顶点Q∪{s}的隐式图上运行Dijkstra,并且对于每个q∈Q,长度为D'的边(i, q)从超级源s到q,并且对于每个q∈Q和a∈Σ,长度为1的边从q到δ(q,a)。设D(i,q)为最终距离。


我相信这个算法,如果实现得很好(专门用于支持单位长度的Dijkstra的堆),运行时间为O(| Q | | w | |Σ|),对于小字母Σ,可比较通常的Levenshtein DP。

答案 1 :(得分:0)

我建议你使用dynamic programming作为这个。 dp是二维的:xi - 你所在的xpattern字符串中的索引和yi - 你所在的y字符串中的索引,每个子问题的值是子字符串x [xi..x之间的最小编辑距离。 size-1]和y [yi ... y.size-1]。

以下是在解释固定y字符串时,如何找到x模式之间的最小编辑距离。我将假设x模式中的符号@表示任意正数的零。此外,我将使用一些全局变量来使代码更容易阅读。

#include <iostream>
#include <string>
using namespace std;


const int max_len = 1000;
const int NO_SOLUTION = -2;
int dp[max_len][max_len];

string x; // pattern;
string y; // to compute minimum edit distance to
int solve(int xi /* index in x */, int yi /* index in y */) {
  if (yi + 1 == y.size()) {
    if (xi + 1 != x.size()) {
      return dp[xi][yi] = NO_SOLUTION;
    } else {
      if (x[xi] == y[yi] || (y[yi] == '0' && x[xi] == '@')) {
        return dp[xi][yi] = 0;
      } else {
        return dp[xi][yi] = 1; //  need to change the character 
      }
    }
  }
  if (xi + 1 == x.size()) {
    if (x[xi] != '@') {
      return dp[xi][yi] = NO_SOLUTION;
    }
    int number_of_ones = 0;
    for (int j = yi; j < y.size(); ++j) {
      if (y[j] == '1') {
        number_of_ones++;
      }
    }
    return dp[xi][yi] = number_of_ones;
  }
  int best = NO_SOLUTION;
  if (x[xi] != '@') {
    int temp = ((dp[xi + 1][yi + 1] == -1)?solve(xi + 1, yi +1):dp[xi + 1][yi +1]);
    if (temp != NO_SOLUTION && x[xi] != y[yi]) {
      temp++;
    }
    best = temp;
  } else {
    int temp = ((dp[xi + 1][yi + 1] == -1)?solve(xi + 1, yi +1):dp[xi + 1][yi +1]);
    if (temp != NO_SOLUTION) {
      if (y[yi] != '0') {
        temp++;
      }
      best = temp;
    }

    int edit_distance = 0; // number of '1' covered by the '@'

    // Here i represents the number of chars covered by the '@'
    for (int i = 1; i < y.size(); ++i) {
      if (yi + i >= y.size()) {
        break;
      }
      int temp = ((dp[xi][yi + i] == -1)?solve(xi, yi + i):dp[xi][yi + i]);
      if (temp == NO_SOLUTION) {
        continue;
      }
      if (y[yi] != '0') {
        edit_distance++;
      }
      temp += edit_distance;
      if (best == NO_SOLUTION || temp < best) {
        best = temp;
      }
    }
  }
  return best;
}

int main() {
  memset(dp, -1, sizeof(dp));
  cin >> x >> y;
  cout << "Minimum possible edit distance is: " << solve(0,0) << endl;
  return 0;
}

希望这有帮助。