Problem50—Pow(x,n)
Disciption
Implement pow(x, n).
Trap
n的输入为int型,当n为MIN_INT时,取反之后会溢出
Solution
- Brute
暴力计算 xn - Binary
二分法 - Bit
位操作法
Code
- Code for Brute
//迭代版本
class Solution {
public:
double myPow(double x, int n)
{
double ans = 1.0;
bool flag = true;
if(n < 0)
{
flag = false;
ans = ans*x;
n = -n-1;
}
while(n)
{
ans = ans*x;
n--;
}
if(!flag)
return 1.0/ans;
return ans;
}
};
//递归版本
class Solution {
public:
double myPow(double x, int n)
{
if(n==0)
return 1.0;
if(n<0)
return 1.0/(myPow(x,-n-1)*x);
return x*pow(x,n-1);
}
};
显然暴力法求解的时间复杂度为 O(n) ,提交过去就直接RE了。
- Code for Binary
采用二分法的思想,根据 xn=xn/2×xn/2×xn%2 (n可为奇数或偶数)这个递归公式,可以很容易写出代码,时间复杂度为 O(log(n)) 。
//版本1
class Solution {
public:
double myPow(double x, int n)
{
//终止条件
if(n < 0)
return 1.0/(myPow(x,-n-1)*x); //当n取值为INT_MIN时,直接取反可能会溢出
if(n == 0)
return 1.0;
if(n == 1)
return x;
//递归
double res = myPow(x,n/2);
return res*res*myPow(x,n%2);
}
};
代码十分简洁易懂,但这种算法将n为奇数和偶数的情况合并在一起,会引起无必要的递归出现,占用递归栈的空间。比如当n取值为65,用这种解法将会无谓地调用多次myPow(x,0)。基于这一点,我们可以将n分奇偶递归,代码如下。
//版本2
class Solution {
public:
double myPow(double x, int n)
{
double res = 1.0;
//终止条件
if(n < 0)
return 1.0/(myPow(x,-n-1)*x); //当n取值为INT_MIN时,直接取反可能会溢出
if(n == 0)
return 1.0;
//递归
if(n%2 == 1)
{
res = myPow(x,n/2);
return res*res*x;
}
else
{
res = myPow(x,n/2);
return res*res;
}
}
};
- Code for Bit
最后一种解法比较巧妙,考虑n为129,写成二进制的形式为10000001, x10000001 等价于 x8×x1 ,当n的二进制位上为0时,实际上只是乘以1。所以我们只需要对n进行右移操作,然后判断n的最低位是否为1,代码如下。
class Solution {
public:
double myPow(double x, int n)
{
if(n < 0)
return 1.0/(pow(x,-n-1)*x);
if(n == 0)
return 1.0;
double res = 1.0 ;
//循环移位
for(;n > 0; x *= x, n>>=1)
{
if(n&1 == 1) //判断n的最低位是否为1
res *= x;
}
return res;
}
};
Tips
- C++中需要采用精确的除法时,只需要保证除数和被除数中有一个为浮点数即可。
- 使用递归算法时,一定要注意列出递归表达式和终止条件。