【问题标题】:What is an efficient way to measure similarity between two strings? (Levenshtein Distance makes stack too deep)测量两个字符串之间相似性的有效方法是什么? (Levenshtein 距离使堆栈太深)
【发布时间】:2011-12-24 03:21:10
【问题描述】:

所以,我从这个开始:http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#Ruby

这对于非常小的字符串非常有用。但是,我的字符串长度可能超过 10,000 个字符 - 由于 Levenshtein 距离是递归的,这会在我的 Ruby on Rails 应用程序中导致堆栈过深错误。

那么,是否还有另一种可能不需要堆栈密集型的方法来查找两个大字符串之间的相似性?

或者,我需要一种方法来使堆栈具有更大的大小。 (不过,我认为这不是解决问题的正确方法)

【问题讨论】:

  • 在您链接的页面上,有很多实现。它们中的大多数不是递归的,并且使用少量的固定堆栈空间。只需移植其中一个。

标签: ruby-on-rails string compare similarity levenshtein-distance


【解决方案1】:

考虑使用非递归版本以避免过多的调用堆栈开销。 Seth Schroeder 有一个 iterative implementation in Ruby,它使用多维数组;它似乎与 Levenshtein 距离的动态规划方法有关(如pseudocode for the Wikipedia article 中所述)。 Seth 的 ruby​​ 代码转载如下:

def levenshtein(s1, s2)
  d = {}
  (0..s1.size).each do |row|
    d[[row, 0]] = row
  end
  (0..s2.size).each do |col|
    d[[0, col]] = col
    end
  (1..s1.size).each do |i|
    (1..s2.size).each do |j|
      cost = 0
      if (s1[i-1] != s2[j-1])
        cost = 1
      end
      d[[i, j]] = [d[[i - 1, j]] + 1,
                   d[[i, j - 1]] + 1,
                   d[[i - 1, j - 1]] + cost
                  ].min
      next unless @@damerau
      if (i > 1 and j > 1 and s1[i-1] == s2[j-2] and s1[i-2] == s2[j-1])
        d[[i, j]] = [d[[i,j]],
                     d[[i-2, j-2]] + cost
                    ].min
      end
    end
  end
  return d[[s1.size, s2.size]]
end

【讨论】:

  • 那个类变量是干什么用的? @@damerau ?它没有在任何地方定义
  • 正如他的博客文章所解释的,有一种替代算法可以使用:“Levenshtein 距离算法将 'seht' 中的 'ht' 视为两个替换。Damerau-Levenshtein 算法将其视为一次交换。否则它是相同的,所以 Damerau-Levenshtein 似乎是更好的方法。如果您想使用经典的 Levenshtein 算法,您可以简单地删除该代码块。
  • 或者如果我想使用效率更高的版本,除非@@damerau,否则只注释下一个?
  • @TheLindyHop:当然,虽然它效率不高(实际上需要更多“工作”)——它只是将两个带有转置字符的字符串视为“差异较小”。
猜你喜欢
  • 2012-07-25
  • 2011-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-21
  • 2013-04-25
相关资源
最近更新 更多