递归计算pow(x,n)比蛮力更好吗?

时间:2015-11-12 20:54:37

标签: java algorithm

我看到当人们实施public class Solution { public double pow(double x, int n) { if(n == 0) return 1; if(n<0){ n = -n; x = 1/x; } return (n%2 == 0) ? pow(x*x, n/2) : x*pow(x*x, n/2); } } 时,他们总是在下面使用类似的解决方案。我的困惑是,下面的解决方案比较强力倍数x多次n的优势是什么?

{{1}}

5 个答案:

答案 0 :(得分:6)

这种技术正式称为Exponentiation by squaring。它需要的操作少于&#34; flat&#34;通过重复乘法求幂,因此N k 的结果在log 2 k时间内计算。

请注意,虽然此算法的实现通常是递归的,但不一定要这样做。可以使用迭代而不是递归来重写算法,以产生相同的加速:

public static double pow(double x, int n) {
    if(n == 0)
        return 1;
    double y = 1;
    while (n > 1) {
        if (n%2 == 1) {
            y *= x;
        }
        x *= x;
        n /= 2;
    }
    return x*y;
}

Demo.

答案 1 :(得分:4)

此算法在O(log(n))时间内运行,而不是在O(n)时间内运行。如果n是偶数,则通过使用标识x^n = (x^2)^(n/2)将剩余的工作分成两半。如果n是奇数,它必须进行标准乘法,但是n将在下一次迭代时均匀,因此它们最终平均为log(n)时间。

答案 2 :(得分:4)

它更快。

假设您执行pow(3, 8)

这会调用pow(9, 4)

反过来,这会调用pow(81, 2)

然后pow(6561, 1)

这是我们的第一个奇怪的力量,所以这次我们6561 * pow(43046721, 0),我们得到6561的最终答案。

(如果pow(6561, 1)刚刚返回6561而不是计算43046721,那可能会更好。

与需要七个的明显解决方案相比,这只需要四次乘法。通常,它会将时间复杂度从O(n)降低到O(log n)。这里n是权力,而不是基础。

答案 3 :(得分:4)

当简单地乘以x * x * x * x * ...时,这似乎具有对数复杂度,而不是线性复杂度。

最后,它将导致所需的步骤数量减少(对于更高的x,这将是非常重要的)。

例如,简单的线性方法x^8将导致八个步骤:

step1 = x
step2 = x * step1
step3 = x * step2
step4 = x * step3
step5 = x * step4
step6 = x * step5
step7 = x * step6
step8 = x * step7
return step8

所呈现的版本基本上是这样的:

step1 = x
step2 = step1 * step1 // equal to x * x
step3 = step2 * step2 // equal to x * x * x * x
step4 = step3 * step3 // equal to x * x * x * x * x * x * x * x
return step4

答案 4 :(得分:2)

通过查看这段代码可以很容易地发现,此函数的算法复杂度 O(log2(n)) ,而自然实施会导致(大致) n 操作。

考虑到:

    if(n == 0)
        return 1;
    if(n < 0){
        n = -n;
        x = 1/x;
    }

常量复杂度(O(1),算法中唯一受到您想要提升输入功能影响的部分如下:< / p>

    if (n%2 == 0) {
        return pow(x*x, n/2);
    } else {
        return x*pow(x*x, n/2);
    }

在任何一种情况下,您都会注意到,通过该方法的每次迭代都会导致另一次迭代,直到n到达0。这里也是明显的,使用此算法,n将以对数的速度减少。

例如,以这种方式计算的2^1024将导致大约10次迭代:

pow(2, 1024);
\_pow(4, 512);
  \_pow(16, 256);
    \_pow(256, 128);
      \_pow(65536, 64);
        \_pow(..., 32);
          \_pow(..., 16);
            \_pow(..., 8);
              \_pow(..., 4);
                \_pow(..., 2);
                  \_pow(..., 1);

...因此总计大约 10 实际操作,而不是 1024 自然实施。