剑指LeetCode 面试题16. 数值的整数次方(Java 代码)

前往 LeetCode做题

剑指LeetCode 面试题16. 数值的整数次方(Java 代码)_第1张图片

思路

如果使用暴力法很容易超时,可以使用快速幂。

快速幂就相当于二分法一样。我们可以将 2100,可以平均分为 250 x 250 。这样一来,我们就只需要计算一个 ret = 250,之后将得到的结果自乘 ret * ret,就可以得到 2100

这个看似简单,但是可以节省大量的重复计算。

这里主要使用两种方式,一种是递归,一种是迭代的方法。两种解法都需要注意的问题:

  • 给定的 n值可能是负数,即 2-2是等于 1/4的
  • 将 n值从负数转换成正数的时候,可能发生整型溢出 - Integer.MIN_VALUE
  • 当 n=0的时候,当 x=1的时候或 x=0的时候,预先进行处理可以少进行很多计算。

递归

class Solution {
    public double myPow(double x, int n) {
    	// 如果 n<0,那么 x不能当被除数
        if(x == 0) return 0;
        // 任何数字的 0次方都等于 1
        if(n == 0) return 1;
        
        // 当 n = Integer.MIN_VALUE的时候,取反会发生 Integer数据溢出,所以用另一个 long类型接收它
        long b = n;
        if(b < 0){
            b *= -1;
            x = 1/x;
        }
        return helper(x, b);
    }

    public double helper(double x, long pow){
    	// 递归的返回条件,递归一般都是需要返回条件的,要不然就会无限递归下去。。。
        if(pow == 1) return x;
        // 计算当前 x的 pow/2 次方,之后将返回的结果自乘就可以得到 x的 pow次方
        double ret = helper(x, pow/2);
        ret *= ret;
        // 不过这里需要注意,如果 pow是奇数,那么结果 ret中就少乘了一次 x,补上
        if(pow % 2 == 1) return ret*x;
        
        return ret;
    }
}

迭代

这个解法是参考 Krahets’s Blog的,写得非常妙。

  • 判断是不是奇数:使用 if((b & 1) == 1) ...;,任何奇数的最后一位都会是 1
  • b >>= 1; 等价于 b /= 2;
class Solution {
    public double myPow(double x, int n) {
    	// 这里只需要处理 x=0的情况
        if(x == 0) return 0;
        long b = n;
        double res = 1.0;
        if(b < 0) {
            x = 1 / x;
            b = -b;
        }
        while(b > 0) {
            // 如果此次是奇数,那么 x*=x就会少乘以一个 x,这里补上
            // 当最后,终有一天 b会等于 1的,这样 res就可以附上 x的的值了
            if((b & 1) == 1) res *= x;
            x *= x;
            // 相当于 b/2
            b >>= 1;
        }
        return res;
    }
}

你可能感兴趣的:(剑指Offer)