就是实现一个简单的pow(double x, int n),直接一个个的乘当然太过naive,使用二分查找使得时间复杂度为o(lgn)。
话不多说,先上代码:
int symbol = 1;
double origx = x;
if (n == 0 || x == 1.0)
return symbol;
if (n < 0)
symbol *= -1;
n = abs(n);
if (x == -1)
return n % 2 ? -1 : 1;
unsigned int i;
for (i = 2; i <= n; i *= 2)
{
if (fabs(x)<=1e-15)
{
if (symbol == 1)
return 0;
return 1.79769e+308;//numeric_limits<double>::max;
}
/*if (fabs(x) >= 1.79769e+308)
{
if (symbol == 1 )
return x>0 ? 1.79769e+308 : -1.79769e+308;
return 0;
}*/
x *= x;
}
i /= 2;
for (i = n - i; i > 0; i--)
x *= origx;
if (symbol == -1)
return 1.0 / x;
return x;
注意一下double上下边界的判断就可以在leetcode上ac了。我是直接找到离n最近的2^i,然后再一个一个的乘够n次。但是这种办法其实还是挺蠢的,因为如果最后可能与2^m+1只差几次,但是2^m可能非常大,这样也会消耗大量的时间。可以直接使用位运算解决这个问题。下面上代码:
if (n == 0 || x == 1)
return 1.0;
if (x == -1)
return n % 2 ? -1 : 1;
bool isPos = n > 0 ? true : false;
if (!isPos)
n *= -1;
double res = 1.0;
while (n)
{
if (n & 1)
res *= x;
x *= x;
n >>= 1;
}
if (isPos)
return res;
return 1.0 / res;
每次判断n的在2进制上每位的值就可以得知如何得到最后的结果,假设 n= 5=1*2^0+0*2^1+1+*2^2;所以res就是x^1*x^4,十分的巧妙,都没进行上下界判断就过了。这种办法虽然时间复杂度还是o(lgn),但是却比第一种办法少了最后一个一个乘到n的时间,在某些情况将大大的提高效率。