我们先考虑n是非负数的情况:
方法一:迭代法
double pow(double x, int n)
{
int i;
double sum = 1;
for (i = 0; i < n; i++)
sum *= x;
return sum;
}
主要操作为乘法运算。
T(n) = n;
时间复杂度为O(n);
方法二:递归一
double pow(double x, int n)
{
if (n == 0)
return 1;
if (n == 1)
return x;
else
return pow(x, n-1) * x;
}
主要操作为乘法运算。
T(n) = T(n-1) + 1;
T(1) = 0;
T(n) = n-1;
时间复杂度为O(n);
方法三:递归二(使用二分法)
double pow(double x, int n)
{
if (n == 0)
return 1;
if (n == 1)
return x;
if (n % 2)
return pow(x, n-1) * x; //也可以使用return pow(x, (n-1)/2) * pow(x, (n-1)/2) * x; 结果时间复杂度相同。
else
return pow(x, n/2) * pow(x, n/2);
}
主要操作为乘法运算。
先计算n为偶数的时间复杂度:
T(n)= 2T(n/2) + 1;
T(1) = 0;
T(2^k) = 2*T(2^(k-1)) + 1 = 2*(2*T(2^(k-2) + 1)) + 1 = 2^2 * T(2^(k-2)) + 2^1 + 1;
迭代可求得,T(2^k)= 2^k * T(2^0) + 2^(k-1) + 1;
T(n) = n/2 + 1;
时间复杂度为O(n);
n位奇数时的时间复杂度为:
T(n) = T(n-1) + 1;
因为n为奇数,那么n-1一定为偶数,所以T(n)= (n-1)/2 + 2 = n + 3/2;
时间复杂度为O(n);
所以,总的时间复杂度为O(n);
方法四:(递归,二分法,优化)
double pow(double x, int n)
{
if (n == 0) return 1;
if (n == 1) return x;
double v = pow(x, n/2);
if (n % 2)
return v * v *x;
else
return v * v;
}
基本运算为乘法运算。
n为偶数时:T(n) = T(n/2) + 1;n为奇数时:T(n) = T(n/2) + 2;
T(1) = 0;
使用上面类似的分析方法可得出时间复杂度为O(logn);
方法五:进一步优化
double pow(double x, int n)
{
if (n == 0) return 1;
if (n == 1) return x;
if (n % 2)
return pow(x*x, n/2) * x;
else
return pow(x*x, n/2);
}
虽然这个算法的时间复杂度仍然是O(logn)。但是相对于方法三,速度会加快。
接着,考虑n为负数的情况
double myPow(double x, int n)
{
if (n < 0)
return 1.0/pow(x, -n);
else
return pow(x, n);
}
经过测试,除了方法一时间超时外,其他的都可以Accept。可见leetcode对时间复杂度的要求不是非常严格。
要考虑 0次方的问题
0的0次方有争议, 我们返回0
0的负数次方非法