剑指 Offer 16. 数值的整数次方

剑指 Offer 16. 数值的整数次方

1.结果

执行结果:通过显示详情>

执行用时:0 ms ,在所有Java提交中击败了100.00%的用户

内存消耗:40.7MB ,在所有Java提交中击败了44.53%的用户

通过测试用例: 304/304

2.时间花费

一个小时,动态规划超内存,实际上并没有二分,相当于遍历一轮

看答案,用递归能过。

3.思路

  • 思路一:动态规划

    虽然采用了动态规划,每次按对半相乘,但是还是算了n次,因此时间复杂度是O(n)

  • 思路二:递归

    时间复杂度O(log n)

  • 快速幂算法

    二分相乘,时间复杂度O(log n)

    主要用到了这个思路,这个很牛逼。分治法思想。

4.code

4.1 code1

class Solution {
    public double myPow(double x, int n) {
        boolean flag = false;
        if (n < 0){
            flag = true;
            n = -n; 
        }
        if( n == 0){
            return 1;
        }else if( n == 1){
            return flag?1/x:x;
        }
        //动态规划 f(n) = f(n/2) * f(n/2)
        // f(0) = 1
        // f(1) = x
        // f(2) = f(1) * f(1)
        // f(3) = f(1) * f(2)
        // f(4) = f(2) * f(2)

        //这里有个整数最大值的问题,应该不要搞到n+1,后面单独乘一次,
        //但是当n为整型最大值时,又会有内存的问题
        double[] re = new double[n];  
        re[0] = 1;
        re[1] = x;
        for (int i = 1; i < n; i++){
            int num = i/2;
            if(i % 2 == 1){
                re[i] = re[num] * re[num + 1];
            }else{
                re[i] = re[num] * re[num];
            }
        }
        // System.out.println(Arrays.toString(re)) ;
        re[n-1] = re[n-1] * x;
        if(flag) return 1/re[n-1];
        else return re[n-1];
    }
}

4.2 code2

4.3 code3

这里long N = n;很关键,可以解决指数在整型范围的最大值和最小值问题,

尤其是,最小值**-2147483648**,转正数时会报错

public double myPow(double x, int n) {
        long N = n;
        return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
    }

public double quickMul(double x, long N) {
    double ans = 1.0;
    // 贡献的初始值为 x
    double x_contribute = x;
    // 在对 N 进行二进制拆分的同时计算答案
    while (N > 0) {
        if (N % 2 == 1) {
            // 如果 N 二进制表示的最低位为 1,那么需要计入贡献
            ans *= x_contribute;
        }
        // 将贡献不断地平方
        x_contribute *= x_contribute;
        // 舍弃 N 二进制表示的最低位,这样我们每次只要判断最低位即可
        N /= 2;
    }
    return ans;
}

我自己的代码【效果和答案很接近,时间也是接近0】

 public double myPow(double x, int n) {
        // 使用二分相乘
        // 3^13 = 3x (3^2)^6
        //      = 3x (9^2)^3 = 3x 81^3
        //      = 3x81 x(81^2)^1
        // 也就是先取单,然后底平方,指数减半
        // 以此类推
         if ( x == 1) return x;
         if ( n ==-2147483648 ){
             if (x == -1) return 1;
             else return 0;
        }
        if (n == -2147483648) return 0;
     	boolean flag = false;
        if (n < 0) {
            flag = true;
            // 当n = -2147483648时,取绝对值,会超过整型范围
            n = -n;
            System.out.println(n);

        }
        if (n == 0) {
            return 1;
        } else if (n == 1) {
            return flag ? 1 / x : x;
        }
        double result = 1;
        double base = x;
        System.out.println("result" + "\t\t" + "base" + "\t\t" + "n");
        while (n > 1) { //这里可以大于0,然后省掉return上面那句
            if (n % 2 == 1) {
                // 表示是奇数,出一个底,更新指数
                result = result * base;
                n = n - 1;
            } else {
                // 表示指数是偶数,底平方,指数减半
                base = base * base;
                n = n / 2;
            }
            System.out.println(result + "\t\t" + base + "\t\t" + n);
        }
        result = result * base; // while(n > 0)时,可省略这句
        return flag ? 1 / result : result;

    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值