实现 pow(x, n) ,即计算 x 的 n 次幂函数。
示例 1:
输入: 2.00000, 10
输出: 1024.00000
示例 2:
输入: 2.10000, 3
输出: 9.26100
示例 3:
输入: 2.00000, -2
输出: 0.25000
解释: 2-2 = 1/22 = 1/4 = 0.25
说明:
-100.0 < x < 100.0
n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。
第一印象
看到这道题,我们理所当然的就想到了暴力解法,即循环n次不断乘以x。
//超出时间限制(299/304)
double myPow(double x, int n) {
if (0 == n) {
return 1.00000;
}
double result = 1.00000;
bool flag = false;
if (n < 0) {
n = abs(n);
flag = true;
}
while (n > 0) {
result *= x;
--n;
}
if (flag)
result = 1 / result;
return result;
}
当然,我们也理所当然地超时了。
尝试解决
在看答案之前来尝试下自己解决吧。
在遇到很大的n时,大量的乘法浪费了很多时间。在算法中,我们常常可以用空间来换时间,用之前求得的数来计算后面的内容。这时我所想到的方法是将n的各个位上的数提取出来,例如n = 4396,我们可以得到一个数组NumPerBit = [6,9,3,4]。然后我们可以将x的10次方,x的100次方(用x的10次方算出),x的1000次方(用x的100次方算出)·····然后根据n的各位数的大小来循环乘以对应位的值,例如对于第i位:((x10)i)^(NumPerBit[i])。这样我们只需首先将x的10的倍数次幂的值算出,然后根据每位的值不断相乘即可。
/*
执行结果:通过
执行用时:4 ms, 在所有 C++ 提交中击败了40.59%的用户
内存消耗:6.2 MB, 在所有 C++ 提交中击败了24.89%的用户
最快的一次:
执行结果:通过
执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:6.3 MB, 在所有 C++ 提交中击败了7.75%的用户
*/
double PowSet[10];//用于保存x^10,x^100,x^1000......
int NumPerBit[10];//用于保存n每位的值
double myPow(double x, int n) {
if (0 == n) {
return 1.00000;
}
double result = 1.00000;
bool flag = false;
long long longN = (long long)n;
if (longN < 0) {
longN = abs(longN);
flag = true;
}
//将n按位拆解
int bits_n = 0;//n的位数
//cout << "n = " << longN << endl;
while (longN) {
NumPerBit[bits_n] = longN % 10;
longN /= 10;
++bits_n;
}
//cout << "NumPerBit = ";
//for (int i = 0; i < bits_n; ++i) {
// cout << NumPerBit[i] << "\t";
//} cout << endl;
for (int i = 0; i < bits_n; ++i) {
PowSet[i] = 1.00000;
}
PowSet[0] = x;
for (int i = 1; i < bits_n; ++i) {//算出x的10^n(n = [1-9])次幂的值
for (int j = 0; j < 10; ++j) {
PowSet[i] *= PowSet[i - 1];
}
}
//cout << "PowSet = ";
//for (int i = 0; i < bits_n; ++i) {
// cout << PowSet[i] << '\t';
//} cout << endl;
for (int i = 0; i < bits_n; ++i) {
for (int j = 0; j < NumPerBit[i]; ++j) {
result *= PowSet[i];
}
}
if (flag)
result = 1 / result;
return result;
}
成功通过!而且在快的时候能够击败100%,可见这个方法执行速度还不错。
是时候看答案了!
快速幂算法
标答使用的是快速幂算法,其实这个方法与刚刚的方法很类似。区别主要在于快速幂是按二进制位数来进行的,而我的方法是用十进制进行的。因此我的方法对于每一位都需要循环10次,而快速幂仅仅只需要一次就行了。而且代码相对而言要简单得多。
//快速幂
double myPow(double x, int n) {
long long LongN = (long long)n;
bool flag = false;
if (LongN < 0) {
LongN = abs(LongN);
flag = true;
}
double result = 1.00000;
while (LongN) {
result *= (LongN%2? x:1);
x *= x;
LongN >>= 1;
}
if (flag)
result = 1.0 / result;
return result;
}