Pow(x, n)【多解法】

实现 pow(x, n) ,即计算 x 的 n 次幂函数。

示例 1:

输入: 2.00000, 10
输出: 1024.00000

示例 2:

输入: 2.10000, 3
输出: 9.26100

示例 3:

输入: 2.00000, -2
输出: 0.25000
解释: 2-2 = 1/22 = 1/4 = 0.25

说明:

  • -100.0 < x < 100.0
  • n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。

方法一:暴力法

思路

只需模拟将 x 相乘 n 次的过程。
如果 n<0,我们可以直接用 ,−n 来替换 x,n 以保证 n≥0。该限制可以简化我们的进一步讨论。

但我们需要注意极端情况,尤其是负整数和正整数的不同范围限制。

算法

我们可以用一个简单的循环来计算结果。

class Solution {
    public double myPow(double x, int n) {
        long N = n;
        if (N < 0) {
            x = 1 / x;
            N = -N;
        }
        double ans = 1;
        for (long i = 0; i < N; i++)
            ans = ans * x;
        return ans;
    }
};
复杂度分析
  • 时间复杂度:O(n)。我们将 x 相乘 n 次。

  • 空间复杂度:O(1)。我们需要一个变量来存储 x 的最终结果。

方法二:递归快速幂算法

思路

假设我们已经得到了的结果,那么如何才能算出 ?显然,我们不需要再乘上 n 个 x。 使用公式 ,只需要一次计算,我们就可以得到 。这种优化可以降低算法的时间复杂度。

算法

假设我们已经得到了 的结果,现在想要计算 的结果。 设 A 是 的结果,我们可以分别根据 n 的奇偶来讨论 。
如果 n 是偶数,我们可以使用公式 得到
如果 n 是奇数,那么 。
直观地说,我们需要将另一个 x 和结果相乘,所以 。 这种方法可以很容易地用递归实现。 我们称这个方法为“快速幂(Fast Power)”,因为我们最多只需要 次计算就可以得到 。

class Solution {
    private double fastPow(double x, long n) {
        if (n == 0) {
            return 1.0;
        }
        double half = fastPow(x, n / 2);
        if (n % 2 == 0) {
            return half * half;
        } else {
            return half * half * x;
        }
    }
    public double myPow(double x, int n) {
        long N = n;
        if (N < 0) {
            x = 1 / x;
            N = -N;
        }

        return fastPow(x, N);
    }
};
复杂度分析
  • 时间复杂度:。每次我们应用公式 ,n 就减少一半。 因此,我们最多需要 次计算来得到结果。

  • 空间复杂度:。每次计算,我们都需要存储 的结果。 我们需要计算 次,因此空间复杂度为 。

方法三:迭代快速幂算法

思路

使用公式,我们可以将 n 写成一些正整数的和,。如果我们可以快速得到 的结果,那么就可以减少计算 所需的时间。

算法

我们可以利用 n 的二进制表示来更好地理解该问题。设 n 从最低有效位(LSB)到最高有效位(MSB)的二进制表示为 。对于第 i 位,如果 ,那么意味着结果需要乘以 。

看上去这种表示法似乎没有任何改进,因为 。但是使用上面提到的公式,还是可以看到一些差异。最初,对于每个 ,我们可以使用 的结果一步得到 。因为的数目最多为 ,所以我们可以在 的时间内得到所有的。在这之后,对于满足 的所有 i,我们可以用 乘以结果。这也需要 的时间。

递归或迭代的快速幂实际上是实现同一目标的不同方式。关于快速幂算法的更多信息,可以访问它的 wiki1 或百度百科2

class Solution {
    public double myPow(double x, int n) {
        long N = n;
        if (N < 0) {
            x = 1 / x;
            N = -N;
        }
        double ans = 1;
        double current_product = x;
        for (long i = N; i > 0; i /= 2) {
            if ((i % 2) == 1) {
                ans = ans * current_product;
            }
            current_product = current_product * current_product;
        }
        return ans;
    }
};
复杂度分析
  • 时间复杂度:。对于 n 的每个二进制位,我们最多只能乘一次。所以总的时间复杂度为 。

  • 空间复杂度:。我们只需要两个变量来存储 x 的当前乘积和最终结果。

你可能感兴趣的:(Pow(x, n)【多解法】)