我很难在N ^ 2和NlogN之间确定是大O吗?让我失望的是从k <= j开始的第三个嵌套的for循环。我该如何调和?
int Max_Subsequence_Sum( const int A[], const int N )
{
int This_Sum = 0, Max_Sum = 0;
for (int i=0; i<N; i++)
{
for (int j=i; j<N; j++)
{
This_Sum = 0;
for (int k=i; k<=j; k++)
{
This_Sum += A[k];
}
if (This_Sum > Max_Sum)
{
Max_Sum = This_Sum;
}
}
}
return Max_Sum;
}
答案 0 :(得分:4)
这可以通过估计或分析来完成。查看最里面的循环,第二个循环内有j-i
个操作。要获得操作总数,总和为:
(1+N)(2 N + N^2) / 6
使算法为O(N ^ 3)。要估算一下,可以看到有三个循环在某个时刻有O(N)个调用,因此它是O(N ^ 3)。
答案 1 :(得分:2)
让我们首先分析最内层的循环:
for (int k=i; k <= j; k++) {
This_Sum += A[k];
}
此处计数器k
从i
(包括)迭代到j
(包括),因此,这意味着for
循环的主体是{{1 }}次。如果我们假设从数组中获取第j-i+1
个数字是在固定时间内完成的,则算术运算(递增k
,计算k
和This_Sum
之和,然后将A[k]
与k
进行对接,然后在 O(ji)中运行。
j
和This_Sum
语句的初始化不重要:
if
实际上,如果我们可以在恒定时间内比较两个数字,并将一个变量设置为在恒定时间内由另一个值保留的值,那么无论条件是否成立,操作数都是固定的。
现在,我们可以看一下中间的循环,并抽象出最内层的循环:
This_Sum = 0;
// ...
if (This_Sum > Max_Sum) {
Max_Sum = This_Sum;
}
此处for (int j=i; j < N; j++) {
// constant number of oprations
// j-i+1 operations
// constant number of operations
}
的范围从j
到i
,因此这意味着操作总数为:
N
此总和等于:
N
---
\
/ j - i + 1
---
j=i
这是一个arithmetic sum [wiki],它等效于:
N
---
\
(N-j) * (1 - i) + / j
---
j=i
或者当我们扩展它时:
(N - i + 1) × ((1 - i) + (i+N) / 2) = (N - i + 1) × ((N-i) / 2 + 1)
这意味着我们现在可以专注于外部循环:
i2/2 + 3×N/2 - 3×i/2 + N2/2 - N×i + 1
所以现在我们可以再次使用以下方法计算操作次数:
for (int i=0; i<N; i++) {
// i2/2 + 3×N/2 - 3×i/2 + N2/2 - N×i + 1
}
我们可以在此处使用Faulhaber's formula [wiki]来求和,并获得:
N
---
\
/ i2/2 + 3×N/2 - 3×i/2 + N2/2 - N×i + 1
---
i=0
或展开形式:
(N+1)×(N2+5×N+6)/6
这就是 O(n 3 )算法。