【问题标题】:Calculating the complexity of Levenshtein Edit Distance计算 Levenshtein 编辑距离的复杂度
【发布时间】:2013-01-15 17:30:48
【问题描述】:

我整天都在研究Levenshtein Edit Distance 这个简单的python 实现。

def lev(a, b):
    """Recursively calculate the Levenshtein edit distance between two strings, a and b.
    Returns the edit distance.
    """
    if("" == a):
        return len(b)   # returns if a is an empty string
    if("" == b):
        return len(a)   # returns if b is an empty string
    return min(lev(a[:-1], b[:-1])+(a[-1] != b[-1]), lev(a[:-1], b)+1, lev(a, b[:-1])+1)

发件人:http://www.clear.rice.edu/comp130/12spring/editdist/

我知道它具有指数级复杂性,但我将如何从头开始计算该复杂性?

我一直在互联网上搜索,但没有找到任何解释,只有声明它是指数的。

谢谢。

【问题讨论】:

  • 尝试绘制调用树。通常,这可以通过动态编程/记忆来解决。
  • 我已经做到了,但我找不到节点数和指数增长之间的联系
  • 这种幼稚的实现是指数型的,但算法并非必须如此。记忆化使这个多项式。

标签: python algorithm complexity-theory dynamic-programming levenshtein-distance


【解决方案1】:
  1. 绘制调用树(您显然已经完成了)。

  2. 从调用树中提取。对于任意 n,将树的深度 d 确定为 n 的函数。

    此外,确定每个节点平均有多少个分支/子节点,因为 n 接近无穷大;这称为平均分支因子b

  3. 意识到以平均分支因子b访问深度为d的树中的每个节点至少需要b ^ d 操作。用 n 来写这个数字,就输入大小而言,您的复杂度有一个下限。

更具体地说:你一直在递归,直到你碰到一个空字符串,每次去掉一个字符。如果我们把字符串的长度称为mn,那么树的深度就是min(m, n em>)。在调用树中除叶子之外的每个节点处,您恰好递归 3 次,因此在极限情况下,平均分支因子为 3。这给了我们一个 Θ(3^min(m, n)) 节点。最坏的情况发生在 m = n 时,所以我们可以称之为 Θ(3^n)。

这仍然只是复杂度的下限。对于全貌,您还应该考虑递归调用之间完成的工作量。在这个幼稚的代码中,这实际上是线性时间,因为a[:-1] 必须复制(以 Θ(n) 成本)几乎所有 a,给出 Θ(n 3^n) 总复杂度。*

[* 我曾经发现一位 CS 教授在二进制搜索中使用 Python 的切片,结果在时间 Θ(n lg n) 中运行。]

【讨论】:

  • 谢谢你的朋友,这是我看到的问题的最好解释。
最近更新 更多