【问题标题】:Big O Notation for string matching algo用于字符串匹配算法的大 O 表示法
【发布时间】:2011-09-16 09:14:29
【问题描述】:

函数 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)...?

【问题讨论】:

    标签: c++ string algorithm big-o


    【解决方案1】:

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

    f(n) ∈ O(g(n)) 如果存在正实数 c 和正整数 N 使得 f(n) = N

    通过这个定义,我们看到 n 代表一个数字 - 在这种情况下,这个数字是传入的字符串的长度。但是,有一个明显的差异,因为这个定义只提供了单个变量函数 f(n) 和在这里,我们清楚地传入了 2 个具有独立长度的字符串。因此,我们搜索 Big O 的多变量定义。然而,正如 Howell 在 "On Asymptotic Notation with Multiple Variables" 中所展示的那样:

    “不可能为多变量函数定义大 O 表示法以隐含所有这些 [通常假定的] 属性。”

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

    方法一

    Let x1 = length(s1)
    Let x2 = length(s2)
    

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

    因为乘法是可交换的,所以最坏情况 foo(s1,s2) == 最坏情况 foo(s2,s1)。因此,我们可以不失一般性地假设 x1 >= x2。 (这是因为,如果 x1

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

    对于最坏的情况(其中 s1 和 s2 不包含公共字符),我们可以在遍历循环之前确定 length(s1) 和 length(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) 是多项之和,则保留增长率最大的一项,其余的则省略。

    结论

    对于n = x1(我们的限制变量),例如x1 >= x2,最坏的情况是x1 = x2。 因此:f(x1) ∈ O(n²)

    额外提示

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

    O(1)
    O(log log n)
    O(log n)
    O(n^c), 0<c<1
    O(n)
    O(n log n) = O(log n!)
    O(n^2)
    O(n^c)
    O(c^n)
    O(n!)
    

    那么问题是可能最好发布到https://math.stackexchange.com/

    【讨论】:

    • 为什么你认为mn 是一样的?这对我来说没有意义。在数学上,O(mn) 和 O(n^2) 是完全不同的东西。
    • @Sven,@Nightwolf - 它们在数学上不同,但数量级相同(这是O 中的变量所代表的)。由于mn 独立变化,并且它们代表字符串的长度,因此对它们的迭代是线性的。大 O 表示法不区分实际值 - 只是数量级。
    • @NightWolf:这对我来说真的没有意义——看我的回答。 @Ethan:您至少需要解释一下n 在您的答案中实际表示什么,否则O(n^2) 毫无意义。
    • @Sven,嗯 - 对我来说似乎很明显,mn 的意思是字符串的长度 s1s2
    • @Ethan:您是否注意到您提供的参考实际上表明嵌套循环具有复杂性O(m n)
    【解决方案2】:

    在大 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))

    【讨论】:

    • 是的,它有点令人困惑...我认为措辞不佳的问题.. IMO O(MN) 是最好的... 0 我会说如果更长的字符串是 N 那么它只是O(N) 假设 M 很小,随着 N 的增长它变得微不足道..?因此我们真的需要了解输入...猜猜最安全的答案是 O(N^2)...
    • @NightWolf:O(m n) 是唯一描述精确渐近行为的表达式。如果我们保持其中一个字符串的长度固定,它会捕捉到算法实际上是O(n)。但是如果不固定其中一个,仅使用最大长度n 我们可以给出的最严格的界限是O(n^2)——毕竟,这两个字符串仍然有可能具有相同的长度。
    • 答案肯定不是 O(n!)。当参数(在本例中为 s1 和 s2 的长度)接近无穷大时,Big O 测量函数的限制行为。您不能对哪个字符串更大或更小做出任何假设(这并不重要)。请参阅:pages.cs.wisc.edu/~vernon/cs367/notes/… 第 4 项。
    • @Ethan:big-O 符号只定义了一个上限——看看它的定义(1)(2)(3)。而n! 肯定是算法的上限。正如我在回答中所解释的那样,大 O 表示法通常用于表示“最严格的上限”,但这与其实际定义相矛盾。此外,在目前的情况下,最严格的上限是 O(m n),而不是 O(n^2)。
    • 是的,定义:“当参数趋于特定值或无穷大时,函数的限制行为”。由于 O (length(s1) 和 length(s2)) 的参数接近无穷大,length(s1) 和 length(s2) 具有相同的数量级 - 因此具有相同的上限。如果 OP 在他的作业上回答 O(n!),他肯定会被标记为错误的。
    【解决方案3】:

    O(n^2)

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

    【讨论】:

    • 所以换句话说,对于大 O,我们基本上假设 s1 大小 (n) 和 s2 大小 (m) 都非常大......因此我们有 massNumN * massNumM ~ massNum^2...?
    • 只是大O忽略了实际数字,只关心函数的类别(即数量级)。所以因为mn和n^2都是两个线性因子的乘积,所以在大O眼里是一样的。也就是说,是因为它们对计算时间的影响是一样的。
    【解决方案4】:

    这样想:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-23
      • 1970-01-01
      • 2017-07-12
      • 1970-01-01
      • 1970-01-01
      • 2013-11-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多