12
int foo(int n) 
{
    int x=2;
    while (x<n)
    {
        x = x*x*x;
    }

    return x;
}

我需要分析它的时间复杂度。我注意到它n的速度比仅仅快得多log(n)。我的意思是,它做的步骤比做的少O(log(n))。我阅读了答案,但不知道他们是如何得到答案的:它是O(log(log(n)). 现在,您如何处理这样的问题?

4

7 回答 7

9

将其视为递归函数:

f(i) = f(i-1)^3

如果你扩展它:

f(i) = ((f(i-k)^3)^3)[...k times] = f(i-k)^(3^k) = f(0)^(3^i)

函数随着幂次方增长......所以达到某个数字的时间(迭代次数)(即计算函数的倒数)是对数的对数。

与您的示例一样f(0) = 2,我们想知道何时f(i) >= nn输入参数(以及i迭代次数):

f(i) = 2^(3^i) >= n
           3^i >= log_2(n)
             i >= log_3(log_2(n))

因此,要达到 的值n,它会takes log_3(log_2(n))迭代(在处理整数时向上舍入以超过它)。

如果函数是:

f(i) = 2*f(i-1) //e.g. x=2*x

那么模式将是:

f(i) = 2*2*[...k times]*f(i-k) = f(i-k)*(2^k) = f(0)*(2^i)

在这种情况下,函数的倒数将以 2 为底的单个对数。

我的数学不是很严谨,但我希望你能明白。

于 2009-09-16T15:12:44.333 回答
4

想想 x 如何随着循环的迭代次数而变化。每次,你把它立方体。因此,在 i 次迭代后,该值将是 2 立方,再次立方......等等,i 次。让我们用 x(i) 来表示这个表达式。假设 x(0)=2、x(1)=2 3 等(我使用 a b 表示 a 的 b 次方)。

当 x(i)>=n 时,我们就完成了。多久时间?让我们解决 i。

首先,我们在两边取对数:ln(x(i))>=ln(n)

ln(x(i)) = ln(x(i-1))*3 = ln(x(i-2))*(3**2) = ... = ln(x(0))*( 3**i)

(以上使用[这个属性][1]:ln(x**b)==ln(x)*b)

所以,3**i * 2 >=ln(n)。让我们取另一个对数:

ln(3**i * 2) = ln(2) + ln(3)*i

所以 ln(2) + ln(3)* i >= ln(ln(n))

现在我们可以求解 i: i >= ( ln(ln(n))-ln(2) ) / ln(3)

我们可以忽略常数因素,得出的结论是我们将采取 log(log(n)) 步骤。这就是你的算法的复杂性。

希望分解所有这样的步骤会有所帮助。

于 2009-09-16T15:23:46.577 回答
2

L3 = 以 3 为底的对数 L2 = 以 2 为底的对数

那么正确答案是O(L3(L2(n))而不是 O(L2(L2(n)))。

x = x * 2开始。x 将呈指数增长,直到达到 n,从而使时间复杂度 O(L2(n))

现在考虑x = x * x。x 比上述增长得更快。在每次迭代中,x 的值都会跳到其先前值的平方。做一些简单的数学运算,我们得到以下结果:

对于 x = 2 n = 4,迭代次数 = 1 n = 16,迭代次数 = 2 n = 256,迭代次数 = 3 n = 65536,迭代次数 = 4

因此,时间复杂度为O(L2(L2(n))。您可以通过将值置于 n 值之上来验证这一点。

现在来解决您的问题,x = x * x * x。这将比 x = x * x 增长得更快。这是表格:

对于 x = 2 n = 8,迭代次数 = 1 n = 512,迭代次数 = 2 n = (512*512*512),迭代次数 = 3 等等

如果你仔细看,结果是O(L3(L2(n))。L2(n) 将得到 2 的幂,但由于你在每次迭代中都取 x 的立方,你将不得不将日志记录到它的基数 3 以找出正确的迭代次数。

所以我认为正确的答案是O(log-to-base-3(log-to-base-2(n))

概括这一点,如果x = x * x * x * x * .. (k times),则时间复杂度为O(log-to-base-k(log-to-base-2(n)

于 2009-09-17T02:05:19.633 回答
1

如果 while 循环内的代码是

x = 2*x;

x 将在 O(log(n)) 次迭代中达到 n。由于您要对 x 进行立方计算,而不是仅仅将其乘以一个常数,因此您会更快地达到 n。

于 2009-09-16T15:02:11.830 回答
1

给定

log ( A * x )     == log ( A ) + log ( x )
log ( x * x * x ) == 3 * log ( x )

所以

log ( log ( x * x * x ) ) == log ( 3 * log ( x ) )
                          == log ( 3 ) + log ( log ( x ) )

这个函数比你的函数快多少或慢多少(通过循环的迭代次数来衡量)?

int log_foo ( int n ) 
{
    double          log_x = log ( 2 );
    const double    log_n = log ( n );

    while ( log_x < log_n )
    {
        log_x = 3 * log_x;
    }

    return exp ( log_x );
}

这个函数会比你的函数快多少或慢多少?

int log_log_foo ( int n ) 
{
    double          log_log_x = log ( log ( 2 ) );
    const double    log_log_n = log ( log ( n ) );
    const double    log_3     = log ( 3 );

    while ( log_log_x < log_log_n )
    {
        log_log_x += log_3;
    }

    return exp ( exp ( log_log_x ) );
}

但是这个函数只增加log_log_x一个常数,所以很容易计算出它做了多少次迭代。

于 2009-09-16T15:21:58.763 回答
1

i为迭代步数和后续步的x(i)值。我们有xi

x(0) = 2
x(i) = x(i-1)³

总步数最大ix(i) < n

我们有

log x(i) = log x(i-1)³
         = 3·log x(i-1)
         = 3·log x(i-2)³
         = 3²·log x(i-2)
         = 3^i·log x(0)
         = 3^i·log 2

⇒  log log x(i) = log (3^i·log 2)
                 = log 3^i + log log 2
                 = i·log 3 + log log 2

对数是严格递增的,所以

x(i) < n ⇔        log log x(i) < log log n
         ⇔ i·log 3 + log log 2 < log log n
         ⇔                   i < (log log n - log log 2) / log 3 ∈ O(log log n)
于 2009-09-17T16:19:58.097 回答
0

为什么不添加一个计数器变量来计算循环的迭代次数。在函数返回之前打印出来。

然后为一系列值调用该函数,例如从 3 到 1,000,000 开始。然后使用GNUPlot 之类的东西绘制结果。

然后查看图形是否与已知曲线匹配。

于 2009-09-16T15:02:34.290 回答