字符串匹配算法的大O表示法

时间:2011-06-16 13:21:16

标签: c++ string algorithm big-o

函数foo的大O符号是什么?

int foo(char *s1, char *s2)
{
   int c=0, s, p, found;
   for (s=0; s1[s] != '\0'; s++)
   {
      for (p=0, found=0; s2[p] != '\0'; p++)
      {
         if (s2[p] == s1[s])
         {
            found = 1;
            break;
         }
      }
      if (!found) c++;
   }
   return c;
}

函数foo的效率是多少?

a)O(n!)

b)O(n ^ 2)

c)o(n lg(base2)n)

d)O(n)

我会说O(MN)......?

4 个答案:

答案 0 :(得分:6)

它是O(n²),其中n = max(长度(s1),长度(s2))(可以在小于二次时间内确定 - 见下文)。我们来看看教科书的定义:

  

f(n)∈O(g(n))如果存在正实数c和正整数N,则对于所有n> = N

f(n)< = c g(n)

通过这个定义,我们看到n表示一个数字 - 在这种情况下,该数字是传入的字符串的长度。但是,存在明显的差异,因为该定义仅提供单个变量函数{{1}在这里我们清楚地传入2个独立长度的字符串。因此,我们搜索Big O的多变量定义。但是,正如Howell在"On Asymptotic Notation with Multiple Variables"中所证明的那样:

  

“不可能以暗示所有这些[通常假定的]属性的方式为多变量函数定义big-O表示法。”

Big O with multiple variables实际上有一个正式的定义,但这需要超出单个变量Big O的额外约束,并且超出了大多数(如果不是全部)算法课程的范围。对于典型的算法分析,我们可以通过将所有变量绑定到限制变量f(n)来有效地将函数减少为单个变量。在这种情况下,变量(具体地说,长度(s1)和长度(s2))显然是独立的,但可以绑定它们:

方法1

n

当没有匹配时,会发生此函数的最坏情况,因此我们执行x1 * x2迭代。

因为乘法是可交换的,最坏的情况foo(s1,s2)== foo的最坏情况(s2,s1)。因此,我们可以在不失一般性的情况下假设x1> = x2。 (这是因为,如果x1< x2我们可以通过以相反的顺序传递参数来获得相同的结果)。

方法2 (如果您不喜欢第一种方法)

对于最坏的情况(其中s1和s2不包含公共字符),我们可以在迭代循环之前确定长度(s1)和长度(s2)(在.NET和Java中,确定a的长度) string是O(1) - 但在这种情况下它是O(n)),将较大的值分配给x1,将较小的值分配给x2。这里很清楚x1> = x2。

对于这种情况,我们将看到确定x1和x2的额外计算使得这个O(n + 2n)我们使用以下简化规则which can be found here来简化为O(n²):

  

如果f(x)是几个项的总和,则保留增长率最大的项,并忽略所有其他项。

<强>结论

表示Let x1 = length(s1) Let x2 = length(s2) (我们的限制变量),n = x1,最糟糕的情况是x1 >= x2。 因此:x1 = x2

额外提示

对于所有homework problems posted to SO related to Big O notation,如果答案不是以下之一:

f(x1) ∈ O(n²)

然后问题可能最好发布到https://math.stackexchange.com/

答案 1 :(得分:5)

在big-O表示法中,我们总是要定义出现的变量的含义。除非我们定义O(n)是什么,否则n没有任何意义。通常,我们可以省略这些信息,因为从上下文中可以清楚地看到它。例如,如果我们说某些排序算法是O(n log(n))n总是表示要排序的项目数,因此我们不必总是说明这一点。

关于big-O表示法的另一个重要事项是它只给出了一个上限 - O(n)中的每个算法也都在O(n^2)中。符号通常用作“算法具有由表达式给出的精确渐近复杂度(直到常数因子)”的意思,但它的实际定义是“算法的复杂性受给定表达式的限制(达到常数)因子)”。

在您给出的示例中,您将mn作为两个字符串的相应长度。根据这个定义,算法确实是O(m n)。如果我们将n定义为两个字符串中较长字符串的长度,我们也可以将其写为O(n^2) - 这也是算法复杂性的上限。对n的定义相同,算法也是O(n!),但不是O(n)O(n log(n))

答案 2 :(得分:2)

<强>为O(n ^ 2)

在复杂性方面,函数的相关部分是嵌套循环。最大迭代次数是s2长度的s1倍,两者都是线性因子,因此最坏情况下的计算时间是O(n ^ 2),即线性因子的平方。正如Ethan所说,O(mn)和O(n ^ 2)实际上是相同的。

答案 3 :(得分:2)

这样想:

有两个输入。如果函数只是返回,那么它的性能与参数无关。这将是O(1)。

如果函数循环遍历一个字符串,则性能与该字符串的长度线性相关。因此O(N)。

但是该函数在循环中有一个循环。性能与s1的长度和S2的长度有关。将这些长度相乘,得到循环迭代次数。它不再是线性的,它遵循曲线。这是O(N ^ 2)。