题面
给定x, n, 求pow(x, n)。
样例
Example 1:
Input: 2.00000, 10 Output: 1024.00000Example 2:
Input: 2.10000, 3 Output: 9.26100Example 3:
Input: 2.00000, -2 Output: 0.25000 Explanation: 2-2 = 1/22 = 1/4 = 0.25Note:
- -100.0 < x < 100.0
- n is a 32-bit signed integer, within the range [−231, 231 − 1] 要小心。
思路1
暴力遍历,累积
时间复杂度:O(n)
👉超时
1 class Solution { 2 public: 3 double myPow(double x, int n) { 4 if(n == 0) 5 return 1;
res = 1; 6 else if(n > 0) 7 { 8 while(n--) 9 { 10 res *= x; 11 } 12 return res; 13 } 14 else 15 { 16 while(n++) 17 { 18 res *= x; 19 } 20 return 1.0/x; 21 } 22 } 23 };
思路2 : 快速幂
时间复杂度:O(log2n)
算法原理
快速幂的快速在于它保存了上一步的计算结果。
关于abs(), fabs(), labs(), llabs(),参考这里
我们举例说明:
求210
10 = 1010 = 1*23 + 0*22 + 1*21 + 0*20
那么 210 = 21010 = 21*23 + 0*22 + 1*21 + 0*20 = 21*23 * 21*21 = 28 * 22
所以只要我们对 n&1 判断它是0/1(决定是否与x的某次幂相乘),以及右移操作即可实现上述过程。
实际例子
pow(2, 5)
x = 2, res = 1;
5 & 1 -> 1 res *= x -> 2; x *= x -> 4; 5 >> 1 -> 2; (该位为1,乘)
2 & 1 -> 0 x *= x -> 16 2 >> 1 -> 1
1 & 1 -> 1 res *= x -> 32 1 >> 1 -> 0 (该位为1,乘)
stoppow(2, 6)
x = 2, res = 1;
6 & 1 -> 0; x *= x -> 4; 6 >> 1 -> 3;
3 & 1 -> 1; res *= x -> 4; x *= x -> 16; 2 >> 1 -> 1 (该位为1,乘)
1 & 1 -> 1; res *= x -> 64 1 >> 1 -> 0 (该位为1,乘)
stop
0101
1 : res = 1*2; 4
0 : res = 1*2; 4^2
1 : res = 1*2 * 1 * 16; 16^2说的再直白一点,就是x一直在以x*=x,进行1 2 4 8 16次幂,而res到底要不要去乘以x的当前次幂,取决于n&1的结果(如果为1,代表要乘,0不乘),本次结束就转向前一位,即n >> 1, 直到n == 0, stop.
1 class Solution { 2 public: 3 double myPow(double x, int n) { 4 double res = 1.0; 5 if(n == 0 || x == 1.0) 6 return 1; 7 else if(n > 0) 8 { 9 while(n) 10 { 11 if(n & 1) 12 res *= x; 13 x *= x; 14 n >>= 1; 15 } 16 return res; 17 } 18 else 19 { //不得不用更大范围的类型,以应对INT_MIN,而且abs()不合用,可以试一下 20 unsigned int m = llabs(n); 21 while(m) 22 { 23 if(m & 1) 24 res *= x; 25 x *= x; 26 m >>= 1; 27 } 28 return 1.0/res; 29 } 30 } 31 };