我希望尽可能少使用正式定义和简单的数学语言。
我希望尽可能少使用正式定义和简单的数学语言。
这是一个非常简化的解释,但我希望它涵盖了最重要的细节。
假设您的算法处理的问题取决于一些“因素”,例如我们将其命名为N和X。
根据N和X的不同,您的算法将需要进行一些操作,例如在最坏情况下,它需要执行3(N^2) + log(X)
次操作。
由于大O符号不太关心常数因子(即3),因此您的算法的大O符号为O(N^2 + log(X))
。它基本上意味着“您的算法在最坏情况下所需的操作数量随着这个值的变化而变化”。
大O表示任何函数的上限。我们通常用它来表达算法运行时间函数的上限。
例如:f(n) = 2(n^2) +3n 是代表假设算法运行时间的函数,大O表示法基本上给出了这个函数的上限,即O(n^2)。
这种表示法基本上告诉我们,对于任何输入的“n”,运行时间都不会超过大O表示法所表示的值。
另外,我同意以上详细回答的所有内容。希望这能有所帮助!
大O表示一类函数。
它描述了函数在大输入值时增长的速度。
对于给定的函数f,O(f)描述了所有函数g(n),其中你可以找到一个n0和一个常数c,使得所有满足n>=n0的g(n)的值都小于或等于c*f(n)。
简单来说,O(f)是一组函数。也就是从某个值n0开始,增长速度比f慢或者不快的所有函数。
如果f(n)=n,则
g(n)=3n在O(f)中。因为常数因素并不重要。
h(n)=n+1000也在O(f)中,因为对于小于1000的所有值可能更大,但是对于大O只有巨大的输入才重要。
然而i(n)=n^2不在O(f)中,因为二次函数的增长速度比线性函数快。
int sumArray (int[] nums){
int sum=0; // here we've 1 operation
for(int i=0; i < nums.length;i++){ // we've n times
sum += nums[i]; // taking initialization and assignments, 3 ops
}
return sum;
}
T(n) = 3*n + 2
n= 1,000,000 -> T(1,000,000) = 3,000,002
n=1,000,000,000 -> T(1,000,000,000) = 3,000,000,002
n=10,000,000,000 -> T(10,000,000,000) = 30,000,000,002
F(n) = n
。n= 1,000,000 -> F(1,000,000) = 1,000,000
n=1,000,000,000 -> F(1,000,000,000) = 1,000,000,000
n=10,000,000,000 -> F(10,000,000,000) = 10,000,000,000
T(n)
约等于或越来越接近F(n)
,因此常数2
和系数3
变得不那么重要,现在“大O符号”的概念出现了。O(T(n)) = F(n)
O(T(n)) = n
T(n)
的大 O 是 n
,符号表示为 O(T(n)) = n
,它是在 n
变得非常大时 T(n)
的上限。同样的步骤适用于其他算法。在简单的英语中,大 O 就像是小于等于符号。当我们说对于两个函数 f 和 g,f = O(g) 时,它意味着 f <= g。
然而,这并不意味着对于任何 n,都有 f(n) <= g(n)。实际上,它意味着f 在增长方面小于或等于 g。这意味着在某一点之后,如果 c 是常数,则 f(n) <= c*g(n)。而在某一点之后指的是对于所有 n >= n0,其中 n0是另一个常数。
大O符号 - 经济角度。
我最喜欢用的英文词汇来描述这个概念是你在完成一个任务时所支付的价格随着任务规模的增长而增加。
可以把它看作是一种重复性成本,而不是一开始需要支付的固定成本。因为成本只会增长并且不断累加,所以固定成本在整体来看变得微不足道。我们想要衡量它们相对于提供给设置的原材料(问题大小)增长的速度和何时会相应地增加。
然而,如果初始设置成本很高,而您只生产少量产品,您将希望查看这些初始成本 - 这些也被称为常数。
由于这些常数在长期内并不重要,这种语言使我们能够讨论超出我们正在运行的基础设施类型的任务。因此,工厂可以位于任何地方,工人可以是任何人-都没有关系。但是随着输入和输出的增长,工厂的规模和工人数量将成为我们可以长期改变的事物。
因此,这就成为了一个如何运行某物需要花费多少的大局观近似值。由于时间和空间是经济数量(即它们是有限的),因此它们都可以使用这种语言来表示。
技术说明:一些时间复杂度的例子 - O(n)通常意味着如果问题的规模为“n”,我至少需要查看每个部分。O(log n)通常意味着我将问题的大小减半并重复检查,直到任务完成。O(n^2)表示我需要查看一对事物(例如n个人之间在派对上握手)。
f(n) = n+3
,并且我们想知道当n
趋近于无穷大时它的图像是什么样子的,我们只需要舍弃所有常数和低阶项,因为它们在n
变大时不重要。这样就剩下了f(n) = n
,那么为什么我们不能只使用它呢?为什么我们需要寻找一些比我们的f(n) = n+3
函数更高和更低的函数,即大O和大Omega。n
趋近于无穷大时简单地说这个函数只是f(n) = n
是不正确的,所以为了正确描述,我们需要找出包含f(n) = n+3
的区域。我们对图像所在位置并不是很感兴趣,因为较低阶的项和常数并没有显著改变图像的增长,因此换句话说,上下限所包围的区域是我们的f(n) = n+3函数的模糊版本。f(n) = n
函数乘以这个常数,使得对于每个n
输出结果都比原来的函数大(或者更小用于下界),那么该函数就是另一个函数的下限或上限。f(n) = n*C > f(n) = n+3
是的,C = 2
可以做到这一点,因此我们的函数 f(n) = n
可以成为我们的函数 f(x) = x+3
的上界。
对于下界也是如此:
f(n) = n*C < f(n) = n+3
C = -2
将会实现它。
所以,f(x) = n
是 f(x) = x+3
的上限和下限,当它既是大O又是Omega时,它就是Theta,这意味着它是严格绑定的。
因此,大O也可以是 f(x) = x^2
,因为它满足条件 f(n) = n^2*C > f(n) = n+3
。它在我们的 f(n) = n+3
图形之上,但是这个上限和下限之间的区域不像我们之前的界限那样精确。