此函数(f1)的时间复杂度是多少?
我可以看到第一个循环(i = 0)->(n / 4次)第二个循环(i = 3)->(n / 4-3次)...等等,结果是:(n / 3)*(n / 4 +(n-3)/ 4 +(n-6)/ 4 +(n-9)/ 4 ....
我在这里停下来,如何继续?
int f1(int n){
int s=0;
for(int i=0; i<n; i+=3)
for (int j=n; j>i; j-=4)
s+=j+i;
return s;
}
答案 0 :(得分:3)
Big(O)表示法的重要之处在于它消除了“常量”。目的是随着输入量的增长确定趋势,而不必担心特定数字。
将其视为在不知道x轴和y轴的数字范围的图形上确定曲线。
因此,在您的代码中,即使您为每个循环的每次迭代都跳过n
范围内的大多数值,这也是以恒定的速率完成的。因此,无论您实际上跳过了多少,这仍然相对于n^2
进行缩放。
计算以下任何内容都没关系:
1/4 * n^2
0.0000001 * n^2
(1/4 * n)^2
(0.0000001 * n)^2
1000000 + n^2
n^2 + 10000000 * n
在Big O中,这些都等效于O(n^2)
。关键是一旦n
变得足够大(无论可能是多少),所有低阶项和常数因子在“全局”中都将变得无关紧要。
(值得强调的是,这就是为什么在小投入时您应该警惕过分依赖Big O的原因。那时候恒定的间接费用仍然会产生很大的影响。)
答案 1 :(得分:1)
关键观察:内部循环在步骤(n-i)/4
中执行i
次,因此在步骤i/4
中执行n-i
。
现在将i = 3k, 3(k-1), 3(k-2), ..., 9, 6, 3, 0
的所有这些数量相加,其中3k
是3
之前n
(即3k <= n < 3(k+1)
)的最大倍数:
3k/4 + 3(k-1)/4 + ... + 6/4 + 3/4 + 0/4 = 3/4(k + (k-1) + ... + 2 + 1)
= 3/4(k(k+1))/2
= O(k^2)
= O(n^2)
因为k <= n/3 <= k+1
,因此还有k^2 <= n^2/9 <= (k+1)^2 <= 4k^2
答案 2 :(得分:-1)
理论上是“ O(n * n)”,但是...
如果编译器想对其进行优化,该怎么办?
String.join(DELIMITER,
SET1.contains(event) ? VALUE1 : SKIP,
SET2.contains(event) ? VALUE2 : SKIP,
SET3.contains(event) ? VALUE3 : SKIP,
SET4.contains(event) ? VALUE4 : SKIP
);
甚至是这样:
int f1(int n){
int s=0;
for(int i=0; i<n; i+=3)
s += table[i];
return s;
}
然后它也可以是“ O(n)”或“ O(1)”。
请注意,从表面上看,这种优化似乎是不切实际的(由于最坏情况下的内存成本);但是使用足够先进的编译器(例如,使用“整个程序优化”来检查所有调用者,并确定int f1(int n){
if(n <= 0) return 0;
return table[n];
}
始终在某个范围内),这是不可想象的。以类似的方式,并非所有调用方都使用常量(例如,使用足够先进的编译器可以将n
之类的内容替换为x = f1(123);
)。
换句话说;实际上,原始函数的时间复杂度取决于该函数的使用方式以及编译器的优劣。