我知道这个算法的大O复杂度是O(n^2)
,但我不明白为什么。
int sum = 0;
int i = 1; j = n * n;
while (i++ < j--)
sum++;
虽然我们一开始设置了j = n * n
,但在每次迭代中我们将i增加而将j减少,所以最终的迭代次数应该比n*n
要少得多,对吗?
我知道这个算法的大O复杂度是O(n^2)
,但我不明白为什么。
int sum = 0;
int i = 1; j = n * n;
while (i++ < j--)
sum++;
虽然我们一开始设置了j = n * n
,但在每次迭代中我们将i增加而将j减少,所以最终的迭代次数应该比n*n
要少得多,对吗?
每次迭代中,你增加i
并减少j
,这相当于将i
增加2。因此,总迭代次数为n^2 / 2,仍然是O(n^2)。
i
增加是线性的,而 j
增加是二次的。二次增长的速度比线性增长更快,这就是为什么时间复杂度是 O(n^2)。 - jeani
的初始值是一个与n
无关的常量。因此,你不应该那样比较i
和j
。 - Dmytro Shevchenkoj
设置为相同的常量并增加它直到i+j < n^2
来轻松保持逻辑。在问题中编写的递减j
和while条件只是为了检查您是否正在关注逻辑。 - jean大O复杂度忽略系数。例如:O(n)
、O(2n)
和O(1000n)
都是相同的O(n)
运行时间。同样,O(n^2)
和O(0.5n^2)
都是O(n^2)
的运行时间。
在您的情况下,您基本上每次通过循环将计数器增加2(因为j--
与i++
具有相同的效果)。因此,您的运行时间是O(0.5n^2)
,但当您移除系数时,这与O(n^2)
相同。
您将恰好进行 n*n/2
次循环迭代(如果 n
是奇数则为(n*n-1)/2
)。
在大 O 记号中,我们有 O((n*n-1)/2) = O(n*n/2) = O(n*n)
,因为常数因素“不计入”。
您的算法等同于
while (i += 2 < n*n)
...
这是 O(n^2/2)
,与 O(n^2)
相同,因为大O复杂度不关心常数。
设m为迭代次数,则有:
i+m = n^2 - m
化简得:
m = (n^2-i)/2
在大O符号表示中,这意味着复杂度为O(n^2)。
是的,这个算法的复杂度为O(n^2)。
为了计算复杂度,我们有一个复杂度表:
O(1)
O(log n)
O(n)
O(n log n)
O(n²)
O(n^a)
O(a^n)
O(n!)
每一行代表一组算法。一个在O(1)中的算法也在O(n)和O(n^2)中,等等。但反过来则不然。因此,你的算法实现了n*n/2句话。
O(n) < O(nlogn) < O(n*n/2) < O(n²)
所以,包括你的算法复杂度的算法集合是O(n²),因为O(n)和O(nlogn)更小。
例如: 当n=100时,求和为5000。 => 100 O(n) < 200 O(n·logn) < 5000 (n*n/2) < 10000(n^2)
对我的英语表示抱歉。
n*n
,但迭代次数与n*n
成比例。这就是大O符号所表示的意思。 - nicolai
增加1、5还是10,000,将n
翻倍仍会使运行时间增加4倍,这是O(n^2)算法的特征。 - chepnersum == n*n / 2
。 - geometrian