Big O符号给出概率上限?

3
我正在尝试估计以下算法的运行时复杂度:

我正在尝试估计以下算法的运行时复杂度:

for i in range(0, len(arr)):
    for j in range(i+1, len(arr)):
        if distance(arr[i], arr[j]) > 2:
            pass

距离函数的复杂度为min(len(arg1), len(arg2))。理论上,参数的最大长度可以达到N,但实际上通常不超过N的20%。

基于此,我可以将运行时间函数估计为:

f(N) = N*(N/2)*(N*.2)

在大O符号表示法中,这是O(N^2)还是O(N^3)?如果是O(n^3),那么如何证明运行时间在实践中总是更接近于O(n^2)而不是O(n^3)?

谢谢


3
.1*O(N^3) 仍然是 O(N^3),它并不更接近 O(N^2) - mgilson
3个回答

2
你问道:
如果时间复杂度为O(n^3),那么如何证明实践中运行时间总是更接近于O(n^2)而不是O(n^3)?
答案是“更接近”并不重要,只有“大于”和“小于”才重要。
Big O给出了一个上限
如果一个过程的运行时复杂度最终超过c * n^2(其中c是任意常数或更大值,n足够大),那么它不可能是O(n^2)。
这是因为Big-O运算符不是给出估计,而是给出上限。即使一个在常数时间内运行的过程仍然是O(n^3)。 (它也是O(n^2),O(log(n)),O(n!)等)。这是因为对于某些常数乘数c和大的n值,该过程比所有这些运行时间都小。
一个具体的例子
为了使这个问题具体化,请考虑以下内容:
>>> def fa(n):
...     return n * n * n // 10
... 
>>> def f2(n):
...     return n * n
... 
>>> def f3(n):
...     return n * n * n
... 

对于上述运行时和小的nfa仍然小于或等于f2
>>> fa(10), f2(10), f3(10)
(100, 100, 1000)

但如果我们将n乘以10,fa就会超过f2

>>> fa(100), f2(100), f3(100)
(100000, 10000, 1000000)

很容易看出,即使我们通过常数倍增加f2,仍然可以找到一个n值,使得fa(n)更大。

>>> def f2_boost(n, c):
...     return f2(n) * c
... 
>>> fa(1000), f2_boost(1000, 10), f3(1000)
(100000000, 10000000, 1000000000)

为什么使用常数乘法?

你可能仍然会感到困惑,一个运行时间为n^3 * 0.1的程序与一个运行时间为1000 * n^3的程序属于相同的大O类别。毕竟,这两个运行时间之间的绝对差异是巨大的!

这有点难以解释,但当你提醒自己,大O符号应该描述缩放行为时,它开始变得有意义。或者换句话说,大O符号应该描述运行时间如何随着我们更改用于测量的“单位”大小而变化。

让我们举个具体的例子:假设你想知道一幢建筑物的高度。并且假设有人说“哦,它大约300米。”你可能会对这个回答感到满意;你可能不在乎它实际上是315米;300是一个足够好的估计。但是如果他们说“哦,它大约300米......还是300英尺?”你可能会感到更不满意,因为300米是300英尺的三倍以上。

在计算机科学中,当测量时间时,我们恰好遇到了这个问题。事实上,情况甚至更糟。不同的计算机可能比其他计算机快得多或慢得多。如果我们以“计算机执行的计算次数”为单位来测量时间,那么对于一些计算机,我们将使用百分之几秒来测量时间,而对于其他计算机,我们将使用十亿分之一秒来测量时间。如果我们想用不会因这种巨大差异而偏斜的方式描述算法的行为,那么我们需要一个“规模不变”的测量——一个测量,无论我们使用百分之几秒还是十亿分之一秒作为单位,都会给出相同的答案。

大O符号提供了这样的测量。它给我们一种测量运行时间的方法,而不需要太担心我们用来测量时间的单位的大小。实际上,说一个算法是O(n^2)就是说,对于任何等于或大于某个值c的时间单位,存在相应的n值,使得我们的过程在所有更大的n值之前完成c * n^2。

估计运行时间

如果你想讨论估计运行时间,则需要一个称为“大theta”的测量。请查看此答案了解详情。简而言之,大O为任意大的乘数c提供了一个上限;大omega为任意大的乘数c提供了一个下限;大theta给出了一个函数,它根据乘数c的选择定义了上限和下限。

在您的情况下,大O值将为O(n^3),因为您可以选择一个常数乘数c1,使得c1 * n^3始终大于n^3 / 10,并且您可以选择一个常数乘数c2,使得c2 * n^3始终小于n^3 / 10。


1
嘿,非常感谢您提供详细的回答。我想我也可以将其写成f(N) = N * (N/2) * d(N)。如果我可以断言d(N)的上限,这将使它成为大O符号的公平估计。谢谢 :) - Muhammad Ali

1

它仍然是 O(n^3)。也许你会认为O(0.0000001 * n^3)O(n^2)更好,但如果我们讨论一个算法的理论复杂度,那么假设n可以达到10^100,你就会明白O(n^3)在性能方面是“更差”的。


1

arr 的长度为N。

由于原始语句在第二个循环中,让我们看看它运行了多少次。

内部循环第一次运行

N-1

第二次运行N-2次。

第三次运行N-3次。

... ... ...

第(N-1)次运行1次。

显然,总和将为= (N-1)(N)/2 = X(假设)。距离函数执行X次,在渐近分析中,我们考虑最坏情况,这意味着距离函数的复杂度= O(N)。

因此T(N)=((N-1)(N)/ 2 N = Y(假设)

使用大O符号的定义

Yc(N^3),对于所有的n ≥ 1,其中c = 1。

因此T(N) = O(N^3)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接