Leetcode-剑指 Offer 16: 数值的整数次方

题目描述:

实现函数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;
     }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值