实现 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
提示:
-100.0 < x < 100.0
-231 <= n <= 231-1
-104 <= xn <= 104
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题目很简单,但是这道题需要充分考虑边界以及特殊情况,比如x为负的情况,n为负的情况,这些情况都需要考虑进去。
如果这些情况都考虑到了,很容易写下如下题解:
class Solution {
public:
double myPow(double x, int n) {
bool flage = (n >= 0) ? true : false;
double res = 1;
if(x == 0) return 0;
if(x == 1) return 1;
int abs_n = flage ? n : -n;
//int falge_res = ( abs_n%2 == 0) ? 1 :( x >= 0) ? 1 : -1;
if(flage){
while(abs_n--){
res = res*x;
}
}
else{
while(abs_n--)
res = res*(1/x);
}
return res;//*falge_res ;
}
};
但是有个特殊的测试用例过不去:
2.00000
-2147483648
这个测试用例为什么过不去呢?
因为数值在计算机中存储是用补码,稍微有点计算机基础的人都会知道,int32_t 的 正数和负数的范围是不一致,因此,可以先用long型变量拿到n,再对long型数取反就不会溢出了。
long b = n;
.....
int abs_n = flage ? b: -b;
这时候,提交,发现超时了,因为此时的复度是O(n)的复杂度,指数越大,耗时越长,看来题目要求我们降低复杂度。
这时候我们就想起来了二分法,
a^n = a^(n/2)*a^(n/2) n为偶数
a^n = a^((n-1)/2)*a^((n-1)/2)*a n为奇数
如此一来,复杂度降到为了O(log n)。
需要注意,如果n为偶数,除法可以用位移操作,同样,如果n为奇数,(n-1)>>1 == n>>1,所以,用位移的操作的时候可以不减一
递归的思路比较简单,
解释两点,
1:为了简化判断,索性就在函数入口做判断,把数据统一处理成正数来做
2:这里把递归函数单独提出来,方便理解
如下:
class Solution {
public:
double kernel(double x, long n){
if( n == 0) return 1;
if( n == 1) return x;
double res = kernel(x,n>>1);
res = res*res;
if((n & 0x1) == 1)
res = res*x;
return res;
}
double myPow(double x, int n) {
long b = n;
bool flage = (b >= 0) ? true : false;
double res = 1.0;
if(x == 0) return 0;
if(x == 1) return 1;
long abs_n = flage ? b : -b;
if(!flage){
x = 1/x;
abs_n = -b;
}
res = kernel(x,abs_n);
return res;
}
};
递归好理解,但是程序每次递归调用都会一起一定的开销,所以,这里也提供了迭代的方法供参考。
class Solution {
public:
double myPow(double x, int n) {
long b = n;
bool flage = (b >= 0) ? true : false;
double res = 1.0;
if(x == 0) return 0;
if(x == 1) return 1;
long abs_n = flage ? b : -b;
if(!flage){
x = 1/x;
abs_n = -b;
}
while(abs_n > 0){
if( (abs_n&1) == 1) res*=x;
x = x*x;
abs_n = abs_n >> 1;
}
return res;
}
};
前面的步骤一样,也是需要解释两点,
1:n>>1一定要赋值给n,直接n>>1不带副作用,n的数值不会变
2:这里当n为偶数时,x=x*x,并没有赋值给res,会不导致漏掉呢?答案是不会的,因为偶数除2必定为奇数,所以res的数值在abs_n=1的时候更新到。
我们可以先写出递归代码, 再改成迭代的形式。