高效的字符串搜索算法?

时间:2013-05-07 17:09:13

标签: string scala complexity-theory big-o time-complexity

我现在要道歉,因为这个问题听起来很愚蠢,我可能会忽略一些非常明显的事情。总之...

好的,所以我正在自学scala,作为一个学习练习,我决定实现一个方法,确定一个字符串是否包含另一个较小的字符串。我做的第一件事是使用天真的版本,我去了字符串的每个字母,并开始向前检查,看看每个字符是否匹配。那很好。然后我决定实现一种更有效的方法,这就是我提出的方法(不包括特殊情况):

// return true if a is a substring of b
def is_sub(a: String, b: String) : Boolean = {
  for(i <- 0 until b.length-a.length) { // O(n-m)
    if(a.hashCode == b.substring(i,a.length+i).hashCode) return true // O(1) + O(1) + O(1)
  }
  return false
}

首先,有人可以检查我的工作并确保我是对的。我很容易犯愚蠢的错误。其次,您可以检查以确保我的时间复杂性是准确的。假设前两个是我认为它们是为什么在string searching algorithms的维基百科页面上没有提到这个方法?理论上,这应该是O(n-m),不需要预处理空间。

我在哪里搞砸了对这个问题的分析?

2 个答案:

答案 0 :(得分:4)

您发布的代码不保证是正确的。如果两个字符串相等,那么它们的哈希码必须相同,但反之则 not 必然为真。可以找到不同字符串但具有相同哈希码的字符串对。因此,如果您找到与要搜索的字符串具有相同哈希码的子字符串,则您的函数可能会返回错误的答案。

此外,您的复杂性分析有点不正确。计算长度为k的字符串的哈希码需要花费时间O(k)(假设你有一个中等的散列函数!),所以这意味着在循环的每次迭代中你将进行O(n)工作计算你所采用的子字符串的哈希码。由于这样做O(m)次,总时间复杂度为O(mn),而不是O(m - n)。

但是,您所做的与Rabin-Karp string searching algorithm密切相关,{{3}}确实基于散列​​字符串。为了避免在每次迭代中进行O(n)工作,该算法使用滚动哈希函数,该函数可以在一个子字符串中容易地更新到下一个子字符串O(1)。它还有一个额外的检查,以便当前的哈希码与子串的哈希码匹配时,算法实际上会检查每个字符以确保它们匹配。在最坏的情况下,该算法需要时间O(mn),但在平均情况下要快得多(时间为O(m + n))。

希望这有帮助!

答案 1 :(得分:0)

您的算法仍为O(n m)。

设m为模式的长度,n为搜索字符串的长度。

在搜索到的字符串中的每个(n-m)位置,您正在创建子字符串并计算其哈希码。每个都需要迭代m个字符。

复杂性不仅取决于您编写的代码,还取决于您调用的代码。