剑指 Offer 16. 数值的整数次方
难度中等
实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。
示例 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] 。
分析:
(1)当指数为负数时,结果为整次方计算后的倒数
优化:
(1)2 ^ 4可以是222*2,也可以是2^2 * 2^2
(2)当n是偶数时,num^n = num^(n/2) * num^(n/2)
(3)当n是奇数时,num^n = num^(n/2) * num^(n/2+1)
代码(爆栈了):
class Solution {
public:
double myPow(double x, int n) {
if (n == 0) return 1;
if (x == 1.0) return x;
bool needInverse = n < 0 ? true : false;
n = abs(n);
double rst = helper(x, n);
if (needInverse) {
rst = 1.0 / rst;
}
return rst;
}
double helper(double x, int n) {
if (n == 0) return 1;
if (n == 1) return x;
double returnVal = helper(x, n >> 1);
returnVal *= returnVal;
if (n & 0x1 == 1) returnVal *= x;
return returnVal;
}
};
转而使用栈替递归
代码(TM的超时):
class Solution {
public:
double myPow(double x, int n) {
if (n == 0) return 1;
if (x == 1.0) return x;
bool needInverse = n < 0 ? true : false;
n = abs(n);
stack<bool> isOdd;
while (n != 1) {
if (n & 0x1 == 1) isOdd.push(true);
else isOdd.push(false);
n = n >> 2;
}
double rst = x;
while (!isOdd.empty()) {
rst = rst*rst;
//如果这次需要得到的是奇数次方
if (isOdd.top()) {
rst = rst * x;
}
isOdd.pop();
}
if (needInverse) {
rst = 1.0 / rst;
}
return rst;
}
};
问题总结:
(1)使用栈记录n的自乘轨迹也需要消耗大量的时间空间成本
(2)直接在取得n自乘轨迹的途中,边取边为我们的结果相乘
代码:
class Solution {
public:
double myPow(double x, int n) {
if (n == 0) return 1;
if (x == 1.0) return x;
long num = n;
double rst = 1;
if (n < 0) {
num = -num;
x = 1 / x;
}
while (num) {
if (num & 1) rst *= x;
x *= x;
num >>= 1;
}
return rst;
}
};