https://leetcode-cn.com/problems/powx-n/submissions/
- 把x的n次方用x的n/2次方与x的n/2次方相乘优化,这是一个递归的问题。leetcode把他归在了二分的tag里,所以能用除以二来优化的都算二分
- x4=x2*x2;x5=x2*x2*x n为奇数和偶数分开进行下一轮递归
- 递归的结束条件:n一直除以二最终会除到0,n==0返回1。理论上加上n==1直接返回x可以减少一次递归调用,但是leetcode的结果显示并没有优化
第一次错的答案
题目里n有正有负,惯性思维让我把n大于零和n小于零分开讨论。理论上遇到负数要先转成正数计算出结果后在取个倒数,这样会造成溢出的问题,因为有符号数正负区间不对称,负数的范围比正数大一,如果对负数去相反数可能会溢出。
从递归的角度考虑也不要在递归计算doPow前对正负分开讨论。这是一个递归,考虑递归从底向上考虑,比如x的一次方,doPow(x,1)=doPow(x,0)*doPow(x,0)*x,等于x。而x的-1次方,doPow(x,-1)=doPow(x,0)*doPow(x,0),*,也等于x。所以在递归中正负最终的结果是一样的,本质上因为1除以2等于-1除以2,都等于0。所以正数和负数递归的最底下是相同的,而在递归的过程中也不需要考虑n的正负,故在doPow前不需要对n的正负进行讨论。
public class pow_50 { public double myPow(double x, int n) { if (n>0){ return doPow(x,n); }else if (n<0){ return 1/doPow(x,-n); }else { return 1; } } public double doPow(double x,int n){ if (n==0){ return 1; } if (n%2==1){ double half = doPow(x, n / 2); return half * half*x; }else { double half = doPow(x, n / 2); return half*half; } } }
正确答案
class Solution { public double myPow(double x, int n) { if(n == Integer.MIN_VALUE && x==2.0){ return 0.0; } if (n>0){ return doPow(x,n); }else if (n<0){ return 1/doPow(x,-n); }else { return 1; } } public double doPow(double x,int n){ if (n==0){ return 1; } if(n==1){ return x; } if (n%2==1){ double half = doPow(x, n / 2); return half * half*x; }else { double half = doPow(x, n / 2); return half*half; } } }