1. 题目来源
链接:数值的整数次方
来源:LeetCode——《剑指-Offer》专项
2. 题目说明
实现函数 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
解释: = = = 0.25
说明:
- -100.0 < x < 100.0
n
是 32 位有符号整数,其数值范围是[−2^31, 2^31 − 1]
。
3. 题目解析
方法一:快速幂
快速幂模板问题,不再赘述。注意下 n
为负值时不能直接对其乘以负一,会产生整形溢出的问题,需要将 n
重新赋给一个数据范围更大的类型。double
不在考虑范围内,因为位运算只能用于整形
参见代码如下:
// 执行用时 :8 ms, 在所有 C++ 提交中击败了9.43%的用户
// 内存消耗 :8.3 MB, 在所有 C++ 提交中击败了100.00%的用户
class Solution {
public:
double myPow(double x, int n) {
long q = n;
if (n < 0) {
x = 1.0 / x;
q = -q;
}
double res = 1;
while(q) {
if (q & 1) // 位运算只能用于整形
res *= x;
x *= x;
q >>= 1;
}
return res;
}
};
方法二:5行高效递归
快速幂思想,用递归来折半计算:
- 每次把
n
缩小一半,这样n
最终会缩小到 0,任何数的 0 次方都为 1,这时候再往回乘 - 如果此时
n
是偶数,直接把上次递归得到的值算个平方返回即可 - 如果是奇数,则还需要乘上个
x
的值 - 还有一点需要引起注意的是
n
有可能为负数,对于n
是负数的情况,我可以先用其绝对值计算出一个结果再取其倒数即可,但是测试用例中的 ,其绝对值超过了整型最大值,会有溢出错误 - 可以用另一种写法只用一个函数,在每次递归中判断
n
的正负情况针对处理即可
参见代码如下:
// 执行用时 :4 ms, 在所有 C++ 提交中击败了69.36%的用户
// 内存消耗 :8.3 MB, 在所有 C++ 提交中击败了100.00%的用户
class Solution {
public:
double myPow(double x, int n) {
if (n == 0) return 1;
double half = myPow(x, n / 2);
if (n % 2 == 0) return half * half;
if (n > 0) return half * half * x;
return half * half / x;
}
};
方法三:迭代法
让 i
初始化为 n
,然后看 i
是否是 2 的倍数,不是的话就让 res
乘以 x
。然后 x
乘以自己,i
每次循环缩小一半,直到为 0 停止循环。最后看 n
的正负,如果为负,返回其倒数。
在此就很巧妙避免了,n
为负值产生溢出的情况。
参见代码如下:
// 执行用时 :8 ms, 在所有 C++ 提交中击败了9.43%的用户
// 内存消耗 :8.3 MB, 在所有 C++ 提交中击败了100.00%的用户
class Solution {
public:
double myPow(double x, int n) {
double res = 1.0;
for (int i = n; i != 0; i /= 2) {
if (i % 2 != 0) res *= x;
x *= x;
}
return n < 0 ? 1 / res : res;
}
};