我很难找到此功能的时间复杂度:
void foo(int n) {
int i, m = 1;
for (i = 0; i < n; i++) {
m *= n; // (m = n^n) ??
}
while (m > 1) {
m /= 3;
}
}
嗯,迭代的第一个显然是O(n^n)
,对它的解释是因为m started with value 1
,并且自己加倍n
次。
现在,我们使用m = n^n
启动while循环,然后每次将其除以3
。
这意味着,(我猜),log(n^n)
。
假设我到现在为止,我不确定我是否需要求和或乘,但我的逻辑说我需要求和它们,因为它们对每个都是“奇怪的”其他
所以我的假设是:O(n^n) + O(log(n^n)) = O(n^n)
因为如果n非常大,我们可以避免O(log(n^n))
。
嗯,我在这里做了很多假设,我希望这是有道理的。我很想听听你对这个功能的时间复杂性的看法。
答案 0 :(得分:2)
理论上,时间复杂度为O(n log n)
,因为:
for (i=0; i<n; i++)
m *= n;
这将执行n次,最后m=n^n
然后这个
while (m>1)
m /= 3;
将执行log3(n^n)
次n * log3(n)
:
P.S。但这只有在您计算操作次数时才会这样。在现实生活中,计算n^n
需要花费更多的时间,因为数字变得太大了。此外,当你将这些大数字相乘时,你的函数会溢出,而且很可能你会受到int
的最大数量的限制(在这种情况下,复杂性将是O(n)
)
答案 1 :(得分:0)
使用foo(int n)
和32位int
,n
不能超过10,否则m *= n
会溢出。
鉴于n
工作的范围很小,O()似乎没有实际意义。即使使用64位无符号m
,n <= 15
。
所以我认为O(n lg(n))在技术上是正确的,但考虑到int
的约束,可疑代码花费更多时间来执行单printf()
而不是遍历foo(10)
}。 IOWs它实际上 O(1)。
unsigned long long foo(int n) {
unsigned long long cnt = 0;
int i;
unsigned long long m = 1;
for (i = 0; i < n; i++) {
if (m >= ULLONG_MAX/n) exit(1);
m *= n; // (m = n^n) ??
cnt++;
}
while (m > 1) {
m /= 3;
cnt++;
}
return cnt;
}
并想出了
1 1
2 3
3 6
4 9
5 12
6 16
7 19
8 23
9 27
10 31
11 35
12 39
13 43
14 47
15 52