这个实现很简单,就是实现的时候注意细节就可以了。
傻白甜做法
乘方n的取值分成三类情况,大于0,等于0,小于0
逐层递归
漏洞
漏洞一:时间O(n),当n很大时,慢到爆炸
漏洞二:未考虑边界条件n=Integer.MIN_VALUE,这个时候-n赋不进n
public double myPow1(double x, int n) {
if (n > 0)
return myPow1(x, n);
else if (n == 0)
return 1;
else
return 1 / myPow1(x, -n);
}
考虑边界
问题:最小值 n = -2147483648,最大值 n' = -n = 2147483648取不到
解决办法:令 n' = n+1 = -2147483647 。求xn等价于求 xn'*x-1
public double myPow2(double x, int n) {
if (n > 0)
return positivePow2(x, n);
else if (n == 0)
return 1;
else if (n != Integer.MIN_VALUE)
return 1 / positivePow2(x, -n);
else
return 1 / positivePow2(x, -(n + 1)) / x;
}
private double positivePow2(double x, int n) {
if (n == 1)
return x;
double half = positivePow2(x, n / 2);
if (n % 2 == 0) {
return half * half;
} else {
return x * half * half;
}
}
精简代码
算法想法是把 负的幂次方 先写成 正的幂次方, 最后再取倒数。
上述实现的时候特意另外写了一个辅助函数,其实没有必要,完全可以写在一起,调用自身即可。
当n<0时, 不再最后取倒数,而是每次x取成1/x即可调用自身。
对于递归的认识还是不够深入。
double myPow(double x, int n) {
if (n < 0)
return 1 / x * myPow(1 / x, -(n + 1));
if (n == 0)
return 1;
double half=myPow(x, n / 2);
if (n % 2 == 0)
return half * half;
else
return x * half * half;
}
下面这个是人家写的,在x平方的时候仍旧调用了自己,贯彻了递归的想法。
我思考的时候觉得下面和上面的代码应该本质的计算量是一致的,但不知道多一次调用会对效率影响多少。
double myPow(double x, int n) {
if (n < 0)
return 1 / x * myPow(1 / x, -(n + 1));
if (n == 0)
return 1;
if (n == 2)
return x * x;
if (n % 2 == 0)
return myPow(myPow(x, n / 2), 2);
else
return x * myPow(myPow(x, n / 2), 2);
}
最终版
剑指offer有讲解,具体可看P90页。
-
书中考虑了两个问题
指数为负
判断运算是否有效。有时输入数字的乘方本身是无效的,比如0-2就是无效的(处理方式就是做了个boolean flag来记录有效还是无效)
-
细节问题
-
除以2的写法。n/2 可以写作 n>>1
注意是1而不是2,我总是想着是2进制,除以2,所以要右移2,其实是右移1!!!!
-
判断奇偶。 n % 2 == 0 可以写作 (n & 1) == 0
括号不能漏,运算的先后性
位运算
-
核心代码如下
double myPow(double x, int n) {
if (n < 0)
return 1 / x * myPow(1 / x, -(n + 1));
else if (n == 0)
return 1;
else if (n == 1) //这个条件写不写都没关系,写了话返回更早一步
return x;
double half = myPow(x, n >> 1);
half *= half;
if ((n & 1) == 1)
half *= x;
return half;
}
非递归实现
写是写了,但是多用了一个Stack s来记录每次分的份数。比如
19 - 9 - 4 - 2
每次有奇数就说明少乘了一份,所以要记录下来。
切分的时候n>=2的话要继续分,n==1的时候直接返回就可以了。
暂时没想到什么更好的办法。
double myPow3(double x, int n) {
if (n == 0)
return 1;
if (n < 0)
return myPow3(1 / x, -(n + 1)) / x;
Stack<Integer> s = new Stack<Integer>();
for (; n != 1; n /= 2)
s.push(n);
double t = x;
//while (s.peek()!=null) { 出错
while (!s.isEmpty()) {
t *= t;
if (s.pop() % 2 != 0)
t *= x;
}
return t;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。