实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。

示例 1:

输入:x = 2.00000, n = 10
输出:1024.00000
示例 2:

输入:x = 2.10000, n = 3
输出:9.26100
示例 3:

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

解法 2: 二分法

为了方便讨论,假设指数 exponent 是正数。那么递归式如下:

  • 如果 exponent 是偶数,Power(base, exponent) = Power(base, exponent / 2) * Power(base, exponent / 2)

    • 3 = 3 × 3
  • 如果 exponent 是奇数,Power(base, exponent) = base * Power(base, exponent / 2) * Power(base, exponent / 2)

    • 3 = 3 × 3 × 3

对于负指数 exponent 的情况,取其绝对值先计算。将最后结果取倒数即可。

时间复杂度是 O (logN);由于采用递归结构,空间复杂度是 O (logN)。

  1. const myPow = function (x, n) {
  2. const isNegative = n < 0; // 是否是负指数
  3. const result = absMyPow(x, Math.abs(n));
  4. return isNegative ? 1 / result : result;
  5. };
  6. function absMyPow(base, exponent) {
  7. if (exponent === 0) return 1;
  8. if (exponent === 1) return base;
  9. let p = absMyPow(base, Math.floor(exponent / 2));
  10. // 极致优化
  11. return exponent & 0x1 === 1 ? base*p*p : p*p;
  12. }

解法 3: 位运算

第 2 种解法可以转换为迭代写法。迭代写法和位运算有关。

为了理解,假设 base=3exponent= 5
那么 5 的二进制是:101。所以,3 的 5 次方可以写成下图的格式:

16. 数值的整数次方 - 图1
可以看到,对 base 进行自乘,导致 base 的指数每次都扩大 2 倍。与 exponent 的二进制相对应。

以上图为例,整个算法的流程如下:

  1. 结果值 result 初始为 1
  2. base 初始为 3,此时 exponent 的二进制最右位为 1,result更新结果为:base * result
  3. exponent 右移一位。base 进行累乘,base 更新为 3 的 2 次方。由于 exponent 的二进制最右位为 0,不更新结果
  4. exponent 右移一位。base 进行累乘,base 更新为 3 的 4 次方。此时 exponent 的二进制最右位为 1,更新结果为:base * result
  5. 结束
  1. var myPow = function (x, n) {
  2. if (n === 0) return 1;
  3. if (n === 1) return x;
  4. const isNegative = n < 0; // 是否是负指数
  5. let absn = Math.abs(n);
  6. let result = 1;
  7. while (absn) {
  8. // 如果n最右位是1,将当前x累乘到result
  9. if (absn & 1) {
  10. result = result * x;
  11. }
  12. x = x * x; // x自乘法
  13. absn = Math.floor(absn / 2); // n右移1位
  14. }
  15. return isNegative ? 1 / result : result;
  16. };