题目描述:
实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。
分析:
这个题第一眼看着好像并不难,但是把它能顺利写下来还是有几处细节要注意的,下面我们就来好好分析以下。
看到这题第一眼我就想着用递归,因为最近想把递归的题好好练练,但是用非递归的方法更简单,我们先来说递归,因为递归会有很多细节。
解法一:递归
这个题的递归方法我一共提交了好几次,还是自己菜啊!
第一次思路:
第一次我就想法比较简单,认为n分为大于0和小于0两种情况,直接每次让n-1(>0)和 n+1(<0)来直接递归,递归出口就是n==0时返回1。
代码:
class Solution {
public double myPow(double x, int n) {
if(n==0)
{
return 1;
}
if(n<0)
{
return 1/x*myPow(x,n+1);
}
return x*myPow(x,n-1);
}
}
自以为是的就提交了,然后结果就是java.lang.StackOverflowError,栈溢出了,也就是如果n的取值太大递归开辟的栈帧太多就导致栈溢出了。
处于这样的结果我又想了想,怎样可以减少递归次数呢?
第二次思路:
每次给N的值除以2,相当于返回结果的X次方就少了一半,那么在给N除以2的时候让下一次递归的X变为本次的平方,这样随着N除以2的次数增加,X的值也是每次平方的增长,这样不就结果也是正确的嘛!
当然了,还是要分n为奇数还是偶数,因为我们每次递归的X都是上一次的平方,如果是奇数的话就要多乘一次方,即需要将它体到前面相乘。
我们以2^8为例来看,见下图所示:
还存在一个问题就是,当n<0时,需要把n转为整数,因为不转为整数的话,每次递归传1/X的话下次递归就会X,所以n为负数不能直接递归。我自己当时就犯了这个错,呜呜~~
来看代码:
class Solution {
public double myPow(double x, int n) {
if(n==0)
{
return 1;
}
if(n<0)
{
//转为整数
return 1/x*myPow(1/x,-n);
}
//return x*myPow(x,n-1);会导致栈溢出
return (n%2==0)?myPow(x*x,n/2):x*myPow(x*x,n/2);
}
}
执行结果,依然是java.lang.StackOverflowError,当时的我啊,太难了,而且报的是n<0那行代码出现栈溢出了,最后才知道原来是整型数值范围的问题导致的栈溢出。
分析原因:
当N取Integer的最小值(Integer.MIX_VALUE=2^31),而整型的取值范围是:-2 ^31 -> 2^31-1。当对Integer.MIX_VALUE转为整数的时候变为2 ^31,但是已经超出了整形的取值范围,这个时候就会转为整型的最小值,即Integer.MIX_VALUE(-2 ^31),也就是他自己,导致一直在自己身上递归,一直开辟栈帧直到栈溢出。
对于整型最大值和最小值之间溢出问题的详细介绍见博客:链接: 解析整型最大值(Integer.MAX_VALUE)溢出变为最小值(Integer.MIN_VALUE).
解决办法:提出一个1/X,给递归调参数的-N变为-N+1!!!
代码:
class Solution {
public double myPow(double x, int n) {
if(n==0)
{
return 1;
}
if(n<0)
{
//转为整数
return 1/x*myPow(1/x,-n-1);
}
return (n%2==0)?myPow(x*x,n/2):x*myPow(x*x,n/2);
}
}
解法二:非递归(循环)
有了上面的递归思路,将其改为非递归其实很容易了。
代码:
public double myPow(double x, int n) {
double result = 1;
if(x == 1.0 || n == 0) return 1.0;
double use = x;
if (n < 0) {
if (x == 0.0) {
return 1/0;
}
if (n == Integer.MIN_VALUE) {
result *= 1 / x;
n = Integer.MAX_VALUE;
}
use = 1 / x;
x = 1 / x;
}
for (int i = Math.abs(n); i > 1;i = i / 2 ) {
if (i % 2 != 0)//为奇数
{
result *= use;
}
use = use * use;
}
return result * use;
}
}