函数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)......?
答案 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)
中。符号通常用作“算法具有由表达式给出的精确渐近复杂度(直到常数因子)”的意思,但它的实际定义是“算法的复杂性受给定表达式的限制(达到常数)因子)”。
在您给出的示例中,您将m
和n
作为两个字符串的相应长度。根据这个定义,算法确实是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)。