有人可以帮我理解如何找到以下循环的时间复杂度:
for (int j = 1 to n) {
k = j;
while (k < n) {
sum += a[k] * b[k];
k += log n;
}
}
我找到了解决方案here n 2 / log(n)。
很明显,外环需要n次,但对于内环,我被卡住了。 n / log n因子来自哪里?
我试图按期限跟进,但无法继续
1st time k = 1,
2nd time k = 1 + log n
3rd time k = 1 + log n + log n // (2 log n)
stuck here :(
我怎样才能找到一个模式或者我应该遵循哪些最佳步骤来获得此类代码的时间复杂度?
答案 0 :(得分:1)
尝试这样思考:外部循环肯定会运行O(n)次,所以如果你可以确定内部循环完成的工作量,你可以将它乘以O(n)得到一个上限完成的工作总数。
让我们看一下内循环。请注意,当循环迭代时,k将采用值j,j + log n,j + 2 log n,...,j + i log n,其中i
是循环具有的迭代次数跑来跑去。
因此,请考虑循环可以执行的最大次数。一旦k≥n就停止,这意味着一旦j + i logn≥n就停止,因此在(n-j)/ log n次迭代后,循环将停止运行。如果我们想要得到这个可能发生的次数的保守上限,请注意在最坏的情况下我们有j = 1.这意味着该循环的最大迭代次数是(n - 1)/ log n = O(n / log n),因此内循环的每次迭代都会执行O(n / log n)工作。
通过O(n)次迭代每次循环迭代乘以O(n / log n)工作产生O(n 2 / log n)的总体结果,这是期望的结果。
希望这有帮助!
答案 1 :(得分:1)
显然,外环以n顺序运行。所以问题是:内循环需要多长时间?循环在k >= n
时终止,k
从j
开始,并以log(n)
的步长递增。大概需要
n / log(n)
以1
为步长从n
到log(n)
求和的迭代(给出或采用舍入误差)。但我们并不总是从1
到n
一直走 - 有时我们会从10
转到n
,或20
或{{1这需要
n/2
当我们从(n - i) / log(n)
开始而不是i
(或1
...)时,我们可以将内部循环显式执行的总次数写为总和:
0
“较小的术语”约为第一个任期的一半
total number = sum(i = 1 to n, (n - i) / log(n))
= sum(i = 1 to n, n / log(n)) - sum( i = 1 to n, i / log(n))
= O(n * n / log(n)) - something smaller than that.
但是当我们看一下计算的顺序时,这个常数并不重要 - 我们只想知道sum( i = 1 to n, i ) = n * (n + 1) / 2;
变大的时候会发生什么,所以你可能想说算法在n
O( (1 - 0.5) * n
2
中运行,我们只是说它在/log(n))
O( n
中运行2
你现在能看到吗?