代码时间复杂度分析

发布于 2024-08-04 20:38:33 字数 292 浏览 4 评论 0原文

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))。现在,你如何处理这样的问题?

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

    return x;
}

I need to analyze its time complexity. I noticed it reaches n much faster than just log(n). I mean, it does less steps than O(log(n)) would do. I read the answer but have no idea how they got to it: It is O(log(log(n)). Now, how do you approach such a question?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

安人多梦 2024-08-11 20:38:33

把它想象成一个递归函数:

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) >= n何时成为n输入参数(以及 i 迭代次数):

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

因此,要达到 n 值,需要 log_3(log_2(n)) 次迭代(round处理整数时要超过它)。

如果函数是:

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 为底的单个对数。

我的数学不是很严格,但我希望你能明白这个想法。

think of it as a recursive function:

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

if you expand it:

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

the function grows as the power of the power... so the time (iterations) to reach a certain number (that is, calculating the inverse of the function) is the logarithm of the logarithm.

As in your example f(0) = 2, we want to know when f(i) >= n being n the input parameter (and i the number of iterations):

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

So to reach a value of n, it takes log_3(log_2(n)) iterations (round up while dealing with integers to surpass it).

if the function would be:

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

then the pattern would be:

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

And in this case, then the inverse of the function would be a single logarithm in base 2.

My math is not very rigorous, but I hope you'll get the idea.

终弃我 2024-08-11 20:38:33

考虑 x 如何随着循环迭代次数的变化而变化。每一次,你都会把它切成立方体。因此,经过 i 次迭代后,该值将是 2 的立方,再次立方......依此类推,i 次。我们用 x(i) 来表示这个表达式。假设 x(0)=2、x(1)=23 等(我使用 ab 表示 a 的 b 次幂)。

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

First, we take a log on both sides: ln(x(i))>=ln(n)

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

(the above uses [this property][1]: ln(x**b)==ln(x)*b)

so, 3**i * 2 >=ln(n). Let's take another logarithm:

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

so ln(2) + ln(3)* i >= ln(ln(n))

Now we can solve for i: i >= ( ln(ln(n))-ln(2) ) / ln(3)

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

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

Think about how x changes with the number of iterations through the loop. Each time, you cube it. So after i iterations, the value will be 2 cubed, cubed again... and so on, i times. Let's use x(i) to denote this expression. Let's say x(0)=2, x(1)=23, etc (I'm using ab to mean a raised to the bth power).

We're done when x(i)>=n. How long does it take? Let's solve for i.

First, we take a log on both sides: ln(x(i))>=ln(n)

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

(the above uses [this property][1]: ln(x**b)==ln(x)*b)

so, 3**i * 2 >=ln(n). Let's take another logarithm:

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

so ln(2) + ln(3)* i >= ln(ln(n))

Now we can solve for i: i >= ( ln(ln(n))-ln(2) ) / ln(3)

We can ignore the constant factors, and we're left with the conclusion that we'll take log(log(n)) steps. That's the complexity of your algorithm.

Hopefully, breaking down all the steps like that helps.

落花浅忆 2024-08-11 20:38:33

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

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

从 < strong>x = x * 2,x 将呈指数增长,直到达到 n,从而使时间复杂度为 O(L2(n))

现在考虑 x = x * x。在每次迭代中,x 的值都会跳到其前一个值的平方,我们得到的结果如下:

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

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

现在来解决您的问题,< strong>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 为底取对数才能找出正确的迭代次数,

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

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

Let

L3 = log to the base 3
L2 = Log to the base 2

Then the correct answer is O(L3(L2(n)) and NOT O(L2(L2(n)).

Start with x = x * 2. x will increase exponentially till it reaches n, thus making the time complexity O(L2(n))

Now consider x = x * x. x increases faster than the above. In every iteration the value of x jumps to the square of its previous value. Doing some simple math, here is what we get:

For x = 2
n = 4, iterations taken = 1
n = 16, iterations taken = 2
n = 256, iterations taken = 3
n = 65536, iterations taken = 4

Thus, the time complexity is O(L2(L2(n)). You can verify this by putting values above values for n.

Now coming to your problem, x = x * x * x. This will increase even faster than x = x * x. Here is the table:

For x = 2
n = 8, iterations taken = 1
n = 512, iterations taken = 2
n = (512*512*512), iterations taken = 3 and so on

If you look at this carefully, this turns out to be O(L3(L2(n)). L2(n) will get you the power of two, but since you are taking cube of x in every iteration, you will have to take log to the base 3 of it to find out the correct number of iteration taken.

So I think the correct answer is O(log-to-base-3(log-to-base-2(n))

Generalizing this, if x = x * x * x * x * .. (k times), then the time complexity is O(log-to-base-k(log-to-base-2(n)

半枫 2024-08-11 20:38:33

如果 while 循环内的代码是

x = 2*x;

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

If the code inside the while loop were

x = 2*x;

x would reach n in O(log(n)) iterations. Since you're cubing x instead of just multiplying it by a constant, you'll reach n faster.

难忘№最初的完美 2024-08-11 20:38:33

鉴于

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 增加一个常量,因此很容易计算出它执行了多少次迭代。

Given

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

So

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

How much faster or slower ( measured by number of iterations of the loop ) will this function be than your function?

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 );
}

And how much faster or slower will this function be than your function?

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 ) );
}

But this function only increments log_log_x by a constant, so it's easy to work out how many iterations it does.

桃扇骨 2024-08-11 20:38:33

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

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

总步数是最大的i,因此x(i) x(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)

Let i be the number of iteration steps and x(i) the value of x after i steps. We have

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

The total number of steps is the biggest i so that x(i) < n.

We have

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

The logarithm is strictly increasing, so

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)
梦明 2024-08-11 20:38:33

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

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

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

Why not add a counter variable to count the number of iterations of the loop. Print it out just before the function returns.

Then call the function for a range of values, e.g. 3 to 1,000,000 to start with. Then plot your result using something like GNUPlot.

Then see if the graph matches a known curve.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文