int n;
int p = 0;
for (int i = 0; i < n; i *= 2) {
p++;
}
for (int j = 0; j < p; j *= 2) {
//code;
}
这是来自Abdul Bari Youtube频道的代码(视频的链接),他们说这个的时间复杂度是O(log),但我认为是O(log),正确答案是什么?
修正初始值。 0
乘以2
将永远不会结束循环。
最后一个循环是o(log log N)
,因为p==log(N)
。 但是,第一个循环是o(logn)
,因此它总共也是o(logn)
。
另一方面,一旦您将一些代码替换为//code
,那么与第二个循环相比,第一个循环可以忽略不计,我们有:
O ( log N + X * log log N)
^ first loop
^ second loop
当x
刚好足够大时,可以将其视为o(log log N)
。 然而严格地说,这是错误的,因为复杂性是关于渐近行为的,无论x
有多大,对于n
到无穷大,logn
在某一点上总是大于x*loglogn
。
PS:我假设//code
不依赖于N
,即它具有恒定的复杂性。 如果不是这样,上述考虑就会改变。
PPS:一般来说,复杂度在设计算法时是很重要的。 在使用算法时,它是相当不相关的。 在这种情况下,对于n
的特定值,您更关心实际运行时。 复杂性可能具有误导性,甚至导致对给定N
的特定用例的错误期望。
的时间复杂度
int n;
int p = 0;
for (int i = 1; i < n; i *= 2) { // start at 1, not at 0
p++;
}
是O(log(n)),因为你做了p++log2(n)次。 对数基数在大O表示法中并不重要,因为它只是按常数缩放。
for (int j = 1; j < p; j *= 2) {
//code;
}
有O(log(log(n)),因为你只能通过乘法循环到p=log(n),所以你有O(log(p)),所以O(log(log(n))。
然而,两者加起来仍然是O(log(n)),因为O(log(n)+log(log(n)))=O(log(n)
你是正确的,完整代码的时间复杂度是O(log(n))。
但是,阿卜杜勒·巴里·西尔也是正确的,因为:-
在视频中,Abdul Sir试图找到循环的第二个的时间复杂度,而不是整个代码的时间复杂度。 再看一遍视频,好好听听他此时在说什么https://youtu.be/9sglbjxqwd4?t=568
再一次,他导出的是第二个循环的时间复杂度,而不是完整代码的时间复杂度。 请听他在视频中9分钟28秒时所说的话。
如果您的困惑是清楚的,请将此标记为正确。