循环运行日志时间时的复杂性

Complexity when loop runs log times

如果我们找到没有。一个数字的因素,我们可以使用以下高效循环。 for(i=1;i<=sqrt(n);i++),其中 n 是要找到其因子的 'no'。这个循环的复杂度为 O(n)。

以下代码片段的时间复杂度是多少? (假设 log(x) returns 以 2 为底数的对数值)。 O(n^2) 还是 O(n logn)? (我假设 log n 是循环除以二时的复杂度。即 i/=2)

void fun()
{
    int i,j;
    for(i=1;i<=n;i++)
        for(j=1;j<=log(i);j++)
            printf("hello world");
}

内部循环调用 printf 大约 log(i) 次,i[1..n]。总调用次数约为

log(1)+log(2)+log(3)+...log(n) = log(n!)

现在,斯特林渐近公式将为您解答。


对于以 2 为底的对数,精确计数由

给出
0 + 1 + 1 + 2 + 2 + 2 + 2 + 3 + 3 + 3 + 3 + 3 + 3 + 3 + 3 + ... + floor(Lg(n))

1.0 + 2.1 + 4.2 + 8.3 + ... + k.floor(Lg(n))

为方便起见,假设 n 的形式为 n=2^m-1,因此最后的 运行 是完整的(和 k=2^(m-1))。

现在从 0m-1x^k 的总和,等于 (x^m-1)/(x-1) 并推导 x 得到 x^k.k。计算 x=2,你得到

s = m.2^m-2^m+2 = (n+1).Lg(n+1)-n+1

对于其他n,您需要为最后一个部分运行添加一个修正项。随着 m=floor(Lg(n+1)):

t = m.(n+1-2.2^m)

您的代码中 "Hello world" 的实际打印数量是:

然后您可以使用 Srinivasa Ramanujan approximation 的 log(n!):

得到整个代码的实际复杂度,即O(n logn)

无需任何数学即可证明 O(n*Log(n)) 的上限。

void fun()
{
   int i,j;
   for(i=1;i<=n;i++)
       for(j=1;j<=log(n);j++)    // << notice I changed "i" to "n" 
           printf("hello world");
}

上面的函数会运行N次内循环,内循环会运行log(N)次。

因此,该函数将 运行 正好 nLog(n) 次。

因为这个函数

 (log(n) + log(n) + ... + log(n)) // n times 

大于 OP 版本

(log(1) + log(2) + ... + log(n))

那就是原版的上界

<= O(n log(n)

评论

还有

(log(n) + log(n) + ... + log(n)) // n times
= log(n^n)
= n*log(n)

j 依赖于 j,因此展开依赖,意味着只分析 i

if i=1 ----> 内循环执行 log(1)

if i=2 ----> 内循环执行 log(2)

if i=3 ----> 内循环执行 log(3)

.

.

if i=n ----> 内循环执行 log(n) 次。

合并它们 ==> log(1)+log(2)+.....+log(n) = log ( 1.2.3...n ) = log ( n! ) = n log(n)