题目
来源: 数值的整数次方
实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。
示例
解题思路及代码
1. 思路
二进制角度:
若n可写成二进制数 n = bm...b3b2b1
,则n = 1*b1 + 2*b2 + 4* b3 + ... +2^(m-1)bm
,所以x^n = x^( 1*b1 + 2*b2 + 4* b3 + ... +2^(m-1)bm) = x^b1 * x^b2 * ... * x^(2^(m-1)bm)
, 所以只用将所有的x^(2^(i-1)* bi)
相乘即可。
代码实现:
在代码实现上主要解决两个问题:1. 求出x^1 x^2 ... x^(2^(m-1))
2. 求出二进制数 b1 b2 ... bm
各位的数,
二分法角度:
快速幂 x^n = x^(n/2) *x^(n/2)
, 每次我们都可以x = x^2
, 直到n为 0 。考虑奇偶问题时,当n为奇数,可先将返回变量先乘以x,再对剩下的n-1次幂进行二分操作。
在代码实现上,如何实现n/2?右移一位,即表示除以2。
2. 代码
二进制角度:
var myPow = function(x, n) {
if (x == 0) {
return 0;
}
if (x == 1.0) {
return x;
}
var a = n;
var res = 1.0;
if (a < 0) {
a = Math.abs(a)
x = 1 / x;
}
while(a) {
if (a & 1) {
res = res * x;
}
x *= x;
a >>= 1;
}
return res;
};
但是一直没提交成功。。。
二分法:
var myPow = function(x, n) {
if (x == 0 || x == 1) {
return x;
}
var a = n;
if (a < 0) {
a = Math.abs(a) // 考虑到n的范围为 -2^31 - (2^31 -1)
x = 1 / x;
}
return absMyPow(x, a);
};
var absMyPow = function(base, exponent) {
if (exponent == 0) {
return 1;
}
if (exponent == 1) {
return base;
}
let subResult = absMyPow(base, Math.floor(exponent / 2));
return exponent % 2 ? subResult * subResult * base : subResult * subResult;
}
myPow 里面的部分还能简化:
var myPow = function(x, n) {
const isNegative = n < 0; // 是否是负指数
const result = absMyPow(x, Math.abs(n));
return isNegative ? 1 / result : result;
}
注意
Math.floor(exponent / 2)
除以2向下取整,其实最快的是 exponent >>= 1