你必须掌握的,快速幂算法

1. 使用快速幂算法实现Pow(x,n)

求x的n次方,可以使用暴力解法,这种算法时间复杂度为O(n),并且,当x和n比较大的时候,可能会存在溢出。

可以使用快速幂的算法

思路
在计算机中,十进制可以和二进制进行转换,利用该原理可将指数转为
在这里插入图片描述
通过快速幂可将指数运算时间复杂度由O(n)降低到O(longn)。

计算xn,将n写成2进制,在计算机中,n就是以2进制的形式存储的,比如计算315,15的二进制形式是1111(0省略)23 + 22 + 21315 = 38 * 34 * 32 * 31 ,这样一来,可以利用迭代法计算315,先算出32,根据32,算出34…,就不需要遍历15次,只需要进行4次循环,也就是n的二进制左边最后一个为1所在的位数。利用n & 1 == 1来判断n的二进制数中每一位是否为1,为1的话就相乘,每次让n向右移一位,直到n=0。如果n为负数的话,就让x = 1 / x,n = -n

代码

 public static double pow(double x, int n) {
        //如果x为0,直接返回0
        if(x == 0) return 0;
        int b = n;
        double res = 1;
        //判断n是否为负数,是负数的话,就让x=1/x,b=-b
        if(b < 0) {
            x = 1 / x; //这里x必须是double类型的,如果是int类型的,x>2, 1 / x 就是0了
            b = -b;
        }
        //开始循环,条件是b不为0
        while(b > 0) {
            //如果b的二进制数某一位是1,就需要res = res * x
            if ((b & 1) == 1) res = res * x;
            //进行迭代计算
            x = x * x;
            //b 向右移1位
            b >>= 1;
        }
        return res;
    }
  • 时间复杂度 O(logn) : 二分的时间复杂度为对数级别。
  • 空间复杂度 O(1) : resres, bb 等变量占用常数大小额外空间。

最不好理解的就是

//开始循环,条件是b不为0
        while(b > 0) {
            //如果b的二进制数某一位是1,就需要res = res * x
            if ((b & 1) == 1) res = res * x;
            //进行迭代计算
            x = x * x;
            //b 向右移1位
            b >>= 1;
        }

比如求39,9转为二进制为1001,39 = 38 * 31 ,也就是只要二进制某一位上为1,就会参与运算,所以这里才会有这个判断if ((b & 1) == 1) res = res * x;,每循环一次,让x = x * x;b >>= 1;,x正好和二进制位数对应。

50. Pow(x, n)大佬题解

2. 快速幂取余

现在oj网站的题或者竞赛的题,如果a的b次幂且b很大,那么题中大多会让你把结果对一个数取余也就是求模,例如a^b%c这种,当然如果是考高精度的题除外。
首先要知道这个公式(a*b) Mod c = [(a Mod c)*(b Mod c)] Mod c,所以,xn % m = (x % m)n Mod c,根据上面的快速幂算法,
xn = x1*b1 * x2*b2 * x4*b2 x8*b3 … (bn是0或1,看n的二进制对应的位置是0还是1)

xn Mod m = ( x1*b1 * x2*b2 * x4*b2 x8*b3 …) Mod m

根据公式可以得出,

xn Mod m = ( x1*b1 * x2*b2 * x4*b2 x8*b3 …) Mod m = ( x1*b1 Mod m )* (x2*b2 Mod m) * (x4*b2 Mod m ) * (x8*b3 Mod m) …) Mod m

观察每一项之间的关系

x2*b2 Mod m = [ (x1*b1 Mod m) * (x1*b1 Mod m) ] Mod m =( x1*b1 )2 Mod m

x4*b2 Mod m = [ ( x2*b2 Mod m ) * ( x2*b2 Mod m ) ] Mod m = ( x2*b2 )2 Mod m

x8*b3 Mod m = [ (x4*b2 Mod m ) * ( x4*b2 Mod m ) ] Mod m = ( x4*b2 )2 Mod m

也就是说,后一项是前一项的平方对m取模,根据递推关系,求出 xn Mod m

代码

 //使用快速幂取余,这里n为正整数,x <<< m
 public static int quickPowMod(int x , int n, int m) {
     if(x == 0) return 0;
     int res = 1;
     while(n > 0) {
     	//如果二进制位为1,就参与运算
         if ((n & 1) == 1) {
             res = (res * x ) % m;
         }
         //进行递推,每一次循环,都要计算更新一次
         x = (x * x ) % m;
         //二进制位移,相当于从右到左读取位b0 b1 b2 b3 b4等等
         n >>= 1;
     }
     return res;
 }

另外,如果m很大的话,代码里的res、x一般都是long类型的,最后转为int
如有不足之处,欢迎指正,谢谢!

  • 13
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值