我试图找出以下2种算法的Big O表示法,但遇到了麻烦。
第一个是:
public static int fragment3 (int n){
int sum = 0;
for (int i = 1; i <= n*n; i *= 4)
for (int j = 0; j < i*i; j++)
sum++;
return sum;
} //end fragment 3
答案应该是O(n^4)
。当我自己尝试这样做时,这就是我得到的:
我查看第一个for循环并认为它运行n^2
logn次。然后对于内部for循环,它运行n次+外循环的运行时间n^3 logn
次。我知道这是错的,但是没有得到它。
对于下面的代码片段,答案是O(n^9)
。
public static int fragment6(int n) {
int sum = 0;
for(int i=0; i < n*n*n; i++) {
if(i%100 == 0) {
for(int j=0; j < i*i; j += 10)
sum++;
} // if
else {
for(int k=0; k <= i; k++)
sum++;
} // else
} // outer loop
return sum;
} // fragment 6
当我尝试它时,我得到:n^3
用于外部for循环。对于if语句,我获得n
,对于第二个for循环,我得到n +
另一个用于循环和if语句,使其成为n^5
。最后,我获得了最终for循环的n,所有内容都加起来O(n^6)
。
我做错了什么以及获得O(n^9)
复杂性的正确方法是什么?
答案 0 :(得分:3)
第一个。
让我们看一下内循环..
在外环(i = 1)的第一次迭代中,它运行1次。在第二次迭代(i = 4),它运行16(4 * 4)次。在第三次迭代(i = 16),它运行256(16 * 16)次。通常,在外循环的第(k + 1)次迭代中,内循环运行次,在该迭代时为。所以迭代的总数将是
现在,我们将拥有多少数字?确定我们应该看一下外循环。在其中我增长为,直到它达到。因此,迭代总数为。
这意味着内循环的总运行次数为
(通过删除总和中的所有数字,但最后一个)。
现在我们知道,内循环至少运行次,因此我们不会比O(n ^ 4)快。
现在,
解决N,
其中C是常数,因此我们不会比O(n ^ 4)慢。
答案 1 :(得分:2)
你计算big-O的方法是错误的,你已经犯了计算错误。
在一些常见情况下,您可以采用最差情况下的迭代次数并将它们相乘,但这不是一种合理的方法,并且对于这样的情况会失败:
for (i = 1; i < n; i *= 2) {
for (j = 0; j < i; j++) {
sum++;
}
}
这里,外循环运行log_2(n)次,内循环最坏情况是n次迭代。所以你使用的错误方法会告诉你这段代码的复杂性是O(n log n)。
正确的方法是精确计算迭代次数,并仅在最后进行近似。迭代次数实际上是:
1 + 2 + 4 + 8 + ... + 2^k
其中2 ^ k是小于n的2的最大幂。该总和为2 ^(k + 1)-1,小于2n。所以准确的复杂性是O(n)。
将这个想法应用到你的第一个例子:
for (int i = 1; i <= n*n; i *= 4)
for (int j = 0; j < i*i; j++)
sum++
i
取值4^0, 4^1, 4^2, ..., 4^k
,其中4^k
是4的最大幂小于或等于n^2
。
对于给定的i^2
值,内循环执行i
次。
总的来说,内部sum++
执行了很多次:
(4^0)^2 + (4^1)^2 + ... + (4^k)^2
= 2^0 + 4^2 + ... + 4^2k
= 16^0 + 16^1 + ... + 16^k
= (16^k - 1) / 15
根据k
的定义,我们有n^2/4 < 4^k <= n^2
。所以n^4/16 < 4^2k <= n^4
,从16^k = 4^2k
开始,我们得到内循环执行的总次数是O(16^k
)= O(n^4
)。
第二个例子可以用类似的方法解决。
答案 2 :(得分:0)
第一种情况:
第二种情况: