一 题目
Implement pow(x, n), which calculates x raised to the power n (xn).
Example 1:
Input: 2.00000, 10 Output: 1024.00000
Example 2:
Input: 2.10000, 3 Output: 9.26100
Example 3:
Input: 2.00000, -2 Output: 0.25000 Explanation: 2-2 = 1/22 = 1/4 = 0.25
Note:
- -100.0 < x < 100.0
- n is a 32-bit signed integer, within the range [−231, 231 − 1]
Accepted 361,215 Submissions 1,263,581
二 分析
medium 级别,求数学的N方运算实现方式。
2.1 直接用乘法实现。
public double myPow(double x, int n) {
double res =1;
if(n==0||x ==1){
return 1.0;
}
if(x==-1){
return n%2==0?1:-1;
}
if( (Math.abs(x)<0.001&& n>1) || Math.abs(x)>1&& n<-100 ){
return 0;
}
for(int i=1;i<=Math.abs( n);i++){
res *= x;
}
if(n<0){
res = 1/res;
}
return res;
}
Runtime: 14 ms, faster than 5.03% of Java online submissions for Pow(x, n).
Memory Usage: 35.4 MB, less than 5.88% of Java online submissions for Pow(x, n).
当然,上面这个不算是正式的解法,不然一点技术含量都没有了。
怎么处理指数式增长呢?没想出来,我开始想移位。不行。。后来看了grandyang大神的文章.
快速幂等法
上面求幂算法之所以时间复杂度非常高(为O(指数n)),就是因为当指数n非常大的时候,需要执行的循环操作次数也非常大。所以我们快速幂算法的核心思想就是每一步都把指数分成两半,而相应的底数做平方运算使用二分或者折半计算,每次把n缩小一半,这样n最终会缩小到0,任何数的0次方都为1,这时候我们再往回乘,如果此时n是偶数,直接把上次递归得到的值算个平方返回即可,如果是奇数,则还需要乘上个x的值。举个例子:2^1000=(2*2)^500,底数只是做了一个操作,遍历次数就少一半。确实利害,尤其是在N很大的时候(不一定实际计算出结果,题目限制了在100以内,否则double表示不了)。
推导下2^10;
=4^5
=4^4*4=16^2*4=256^1*4 =1024
具体实现是递归或者直接循环不重要。如果这个指数运算想不到,那就卡住了。
代码很简洁,甚至不用做上面那么多的判断。简直是跪了。
public double myPow(double x, int n) {
double res = 1.0;
for (int i = n; i !=0; i/=2) {
if (i%2 != 0){
res *= x;
}
x *= x;
}
return n <0 == true ? 1/res : res;
}
Runtime: 0 ms, faster than 100.00% of Java online submissions for Pow(x, n).
Memory Usage: 33.5 MB, less than 5.88% of Java online submissions for Pow(x, n).
网上还有位操作的实现,在本题区别不大。
其中判断奇偶可以使用&1截取最后一位代替%2.
除以2可以右移1位>>1。
不是重点,重点是快速幂的实现。