Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 是否有稀疏编辑距离算法?_Algorithm_Levenshtein Distance - Fatal编程技术网

Algorithm 是否有稀疏编辑距离算法?

Algorithm 是否有稀疏编辑距离算法?,algorithm,levenshtein-distance,Algorithm,Levenshtein Distance,假设有两个长度为100000的字符串,其中包含0和1。您可以在大约10^10次运算中计算它们的值 如果每个字符串只有100个1,其余的都是0,那么我可以用100个整数来表示每个字符串,说明1在哪里 有没有更快的算法来计算编辑距离 这种稀疏表示?更好的算法是使用100^2的空间而不是10^10的空间 给出一些测试,考虑这两个字符串,每个都有10个字符串。整数表示每个字符串中1的位置 [9959, 10271, 12571, 21699, 29220, 39972, 70600, 72783, 81

假设有两个长度为100000的字符串,其中包含0和1。您可以在大约10^10次运算中计算它们的值

如果每个字符串只有100个1,其余的都是0,那么我可以用100个整数来表示每个字符串,说明1在哪里

有没有更快的算法来计算编辑距离 这种稀疏表示?更好的算法是使用100^2的空间而不是10^10的空间

给出一些测试,考虑这两个字符串,每个都有10个字符串。整数表示每个字符串中1的位置

[9959, 10271, 12571, 21699, 29220, 39972, 70600, 72783, 81449, 83262]

[9958, 10270, 12570, 29221, 34480, 37952, 39973, 83263, 88129, 94336]


在算法方面,如果我们有两个长度为
n
的稀疏二进制字符串,每个字符串由
k
整数表示,是否存在
O(k^2)
时间编辑距离算法?

当然!可能的操作太少,0太多。我的意思是,答案最多是200

看看

10001010000000001
vs       ||||||
10111010100000010
看看所有带管道的零。你最终删除其中的哪一个重要吗?不。这是关键


解决方案1

让我们考虑正常的n*m解:

dp(int i, int j) {
    // memo & base case
    if( str1[i-1] == str1[j-1] ) {
        return dp(i-1, j-1);
    }
    return 1 + min( dp(i-1, j), dp(i-1, j-1), dp(i, j-1) );
}
如果几乎每个字符都是0,那么什么会占用最多的时间

if( str1[i-1] == str1[j-1] ) { // They will be equal so many times, (99900)^2 times!
    return dp(i-1, j-1);
}
我可以想象,这种涓涓细流会导致数万次递归。实际上,你所需要的逻辑是~200个临界点。你可以忽略其余的。一个简单的修改就是

if( str1[i-1] == str1[j-1] ) {
    if( str1[i-1] == 1 )
        return dp(i-1, j-1); // Already hit a critical point

    // rightmost location of a 1 in str1 or str2, that is <= i-1
    best = binarySearch(CriticalPoints, i-1);
    return dp(best + 1, best + 1); // Use that critical point
    // Important! best+1 because we still want to compute the answer at best
    // Without it, we would skip over in a case where str1[best] is 1, and str2[best] is 0.
}
这一个非常简单,但我把它留给解决方案二,因为这个解决方案似乎是凭空而来的,而不是分析问题,找出慢的部分在哪里,以及如何优化它。不过,请将其保存在工具箱中,因为您应该编写此解决方案


解决方案3 就像解决方案2一样,我们可以这样做:

dp(int i, int j, int threshold = 205) {
    if( threshold == 0 )
        return 205;
    // memo & base case
    if( str1[i-1] == str1[j-1] ) {
        return dp(i-1, j-1);
    }
    return 1 + min( dp(i-1, j, threshold - 1), dp(i-1, j-1, threshold - 1), dp(i, j-1, threshold - 1) );
}
您可能会担心dp(i-1,j-1)的下降,但阈值使i和j保持在一起,因此它会计算解决方案2的子集。这是因为每次i和j距离越远,阈值就越小
dp(i-1,j-1,阈值)
将使其与解决方案2相同(因此,此方案稍微快一点)


空间 这些解决方案将很快为您提供答案,但如果您也需要空间优化解决方案,则可以很容易地将
str1[i]
替换为
(str1临界点中的i)?1:0,使用哈希映射。这将提供一个最终的解决方案,该解决方案仍然非常快(尽管速度将慢10倍),并且还避免了将长字符串保留在内存中(直到可以在Arduino上运行)。不过,我认为这没有必要

请注意,原始解决方案不使用10^10的空间。您提到“甚至更好,小于10^10空间”,暗示10^10空间是可以接受的。不幸的是,即使有足够的RAM,迭代该空间也需要10^10次,这绝对是不可接受的。我的解决方案中没有一个使用10^10的空格:只有2*10^5来保存字符串-如上所述,这是可以避免的。10^10字节,可供参考10 GB



编辑:正如maniek所指出的,您只需要检查
abs(i-j)>105
,因为将
i
j
相等所需的其余100个插入将使操作数超过200。

虽然更一般,但对压缩对齐进行了大量研究。查看lz或rle压缩字符串上的levenshtein/lcs。后者将允许类似于O(n'*m'+更小的值)的情况,其中这些变量是运行次数(在您的情况下很小)。例如,
Ann,Xing Yen,et al.“计算游程编码字符串最长公共子序列的快速简单算法”,《信息处理快报》108.6(2008):360-364,但不要低估那里的
simple
。我认为在其他一些论文中有一个对列文施坦的概括,我似乎很天真。二进制字符串的编辑距离不是他们的XOR?@ VROMMONDENL号吗?考虑01010101…和10101010。。。。这些关键字也可能缺少LZ变体。如何通过二进制搜索在未排序的子字符串中找到最右边或最左边的“一”?@mangusta好吧,先排序。OnInstrx的位置将是这些参数的索引。您甚至不必对其进行排序以使其高效,循环很好—它已经足够高效了。排序是有意义的,因此您可以轻松地进行二进制搜索。好的,您添加了一个关于排序的编辑,如果您最初通过排序对两个字符串进行修改,如何才能找到它们的编辑距离?“您甚至不必对其进行排序以提高效率,循环很好,已经足够有效了”,在这种情况下,我们得到的是编辑距离的规范版本,不是字符串,而是索引。如果在位置10、15、28处有一个1,而在其他任何地方都有一个0,则OnInstrx的位置类似于[10、15、28]。我们将对该数组进行排序。str1和str2是实际的字符串本身,我们不接触它们。当然,我们可以将所有str1[i]替换为(i位于OnInstrx位置)以减少内存使用。
dp(int i, int j, int threshold = 205) {
    if( threshold == 0 )
        return 205;
    // memo & base case
    if( str1[i-1] == str1[j-1] ) {
        return dp(i-1, j-1);
    }
    return 1 + min( dp(i-1, j, threshold - 1), dp(i-1, j-1, threshold - 1), dp(i, j-1, threshold - 1) );
}