力扣刷题笔记 50 Pow(x, n)

题:
实现 pow(x, n) ,即计算 x 的 n 次幂函数。
(-100.0 < x < 100.0
n 是 32 位有符号整数,其数值范围是 [−2∧31, 2∧31 − 1] 。)

---------------------------------------------------------------------------------------

一个数的n次幂,一般要分三种情况考虑: n < 0, n = 0, n > 0.
通常解法, 暴力法,对n进行循环,时间复杂度是 O(n)

class Solution {
    public double myPow(double x, int n) {
        double base = x;
        if(x==1){
            x=1;
        }
        else if(n>0){
            for(int i=1;i<n;i++){
                x=x*base;
            } 
        }else{
            for(int i=1;i>n;i--){
                x=x/base;
            }           
        }
        return x;
    }
}

这种解法最容易被想到但是由于复杂度是O(n), 当x,n太大的时侯,这种方法就不太适用了。在运行时间上无法通过提交,因此需要寻找更快的方法。
这里引入一个概念 [快速幂] 。本质是分治算法

原理如下:
在这里插入图片描述
将n拆分迭代
在这里插入图片描述

------------------------------------------------------------------------------------------

一,使用递归的方式来实现这个算法 时间复杂度为 O(log n)

class Solution {
    public double myPow(double x, int n) {
        if(x == 1|| n==0){
            return 1;}
        else{
            int temp = n/2;
            double res = myPow(x,temp);
            if(n>0){
                if(n%2==0){
                    res=res*res;
                }
                else{
                    res=res*res*x;
                }
                return res;
            }
            else{
                if(n%2==0){
                    res=res*res;
                }
                else{
                    res=res*res/x;
                }
                return res;
            }
        }
    }
}

该算法在leetcode的结果:
执行用时 :
1 ms, 在所有 Java 提交中击败了94.45%的用户
内存消耗 :
37.2 MB, 在所有 Java 提交中击败了5.88%的用户

对于n=11,x=3时候的递归过程详解
输入计算 311
–> 35 * 35 *3
–> ( 32 * 32 3 ) * (32 * 32 3) 3
–> (( 31
31) * ( 31
31) 3 ) * (( 31 31) * ( 31
31) *3) *3
–> (( (303) (30*3)) * ((303) (30*3)) *3 ) * (( (303) (30*3)) * ( (303)(303)) 3) 3
–> (( (3*3)
(3*3)) * ((3*3)
(3*3)) *3 ) * (((3*3)
(3*3)3)) * ((3*3)*3)(3*3)) *3) *3

------------------------------------------------------------------------------------------

二,不使用递归的方式,用于进一步减少资源的消耗

由于递归时需要不断重复计算 比如 33, 35 的值,消耗了很多不必要的资源 (由于递归需要使用额外的栈空间 )。
此处进行优化。 以311举例,

在递归运算中,
311 <-- 先平方再乘3 – 35 <-- 先平方再乘3– 32 <-- 23

上述过程中

  • 粗体的原始的3,参与了3次平方计算,所以初始的3最后被乘的次数是23
  • 第一次 先平方后乘3 中的3 最后被平方了1次,21
  • 最后一个 先平方后乘3 中的3 没有被平方过,所以是 20

最终得到的结果就是
311 = 328 *321 *320 = 3(1011)2

所以我们可以计算对应的二进制位置为1处对应的幂 作为最后结果的乘数。

class Solution {
    public double myPow(double x, int n) {
        double res = 1;
        double contribute = x;  // 这个用于每次计算  x, x∧2,x∧3.....
        boolean negative = (n<0);
        while(n!=0){
            if(n%2!=0){// 只有当 n的二进制末位是1 的时候,在res中乘入 contribute
                res*=contribute;
            }
            contribute*=contribute;
            n/=2;
        }
        if(negative){
            return 1/res;
        }
        else{
            return res;
        }
    }
}

不知道为何内存消耗没有变。 XD
内存消耗 :37.3 MB , 在所有 Java 提交中击败了 5.88% 的用户

此外,也可以引入 位运算 来优化循环条件,更好的显示逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值