假设我们有一个跟随循环:
for (int i = 0; i < n; i++)
for (int j = i+1; j < n; j++)
for (int k = j+1; k < n; k++)
for (int l = 0; l < n; l++)
我知道第一个循环将循环 n 次。
我认为第二个将会运行(1/2)*(n ^ 2 + n - 2)次,因为我们需要计算从2到2的总和n,而不是从1到n。
但是,我不知道第三和第四个。
答案 0 :(得分:2)
有(至少)两种方式来理解时间复杂度:第一种方法是注意三个嵌套的for循环生成所有3
- n
- 集的子集,以及第二个是“直接”方法。
前三个for循环精确选择所有3
- n
- 集的子集,每个3
- 子集恰好一次(考虑一下)。有(n choose 3) = O(n^3)
个此类子集(请参阅here)。最里面的循环O(n)
适用于其他三个循环的每个O(n^3)
次迭代,因此总时间为O(n^4)
。
三个循环(没有最里面的循环)完全进行n choose 3 = n!/(3!(n-3)!)
次迭代。这正是n*(n-1)*(n-2) / 6
次迭代。
最内层循环将执行n
次,无论其他循环如何,因此时间复杂度为O(n * f(n))
,其中f(n)
是其他三个循环的时间复杂度,如果我们删除最内层的。
两个最里面的循环(j
- 和k
- 索引的循环)一起花费O(i^2)
时间。这很容易看出 - 它与从j=0
到i-1
和k=j
到i-1
的双循环相同,所以时间是{{1 }}
因为outtermost循环从O(1) + O(2) + ... + O(i) = O(i^2)
变为i=0
,所以总复杂度为n-1
,即n * (O(1^2) + O(2^2) + ... + O(n^2))
:outtermost循环(O(n * n^3)
- 已编入索引)执行从i
到j
的双重for循环(k
- 和i=0
- 索引)。
因此我们的总运行时间为i=n-1
。
要获得确切的迭代次数,您必须为合适的O(n^4)
计算术语i*(i-1)/2 = (i^2-i)/2
的总和。我们只是总和,最后除以2。
你可以把它分成两个总和,
i
现在我们除以2得到结果(1^2 + 2^2 + ...n-1) - (1 + 2 + ... + n-1) =
= n(n-1)(2n-1)/6 - n*(n-1)/2 =
= n*(n-1)(n-2)/3
。与上面完全相同。 (见how to compute the sum of first n
squares。)
答案 1 :(得分:0)
第一个循环将重复n次,第二个循环将进行(n-1)次,第三个循环将循环(n-2)次,最后一个循环将进行l次。最后所有人都会去 N *(N-1)*(N-2)*升 次。