C++快速幂详解

快速幂

关于快速幂这一块还是需要做一个总结,写一篇博客捋捋思路,加深理解。

为什么要用快速幂?

例如:现在有一个题目让你求 abab ,你可能觉得很简单啊,来一个for循环,循环b-1次就行了。但是如果b非常大的情况下,那这个做法是非常低效的,时间复杂度大致为 O(b)

当用快速幂之后,时间复杂度为O(logn)

快速幂例子

例如我们用快速幂求 211211

将指数拆分能够得到如下的结果。

211=220+21+23211=220+21+23

学过进制转换看到11拆开的样子肯定会很眼熟,其实这里就是跟二进制有关。

11的二进制为1011 , 11=231+220+211+20111=23∗1+22∗0+21∗1+20∗1

这样一来,我们求211211就不需要算10次了,现在三次就够了。

211=220221223211=220∗221∗223

到这里以后,我们可能会觉得后边的这三项似乎不好求。

不着急,我们先上代码。

int poww(int a,int b){
    int ans=1,base=a;
    while(b!=0){
        if(b&1!=0)
          ans*=base;
        base*=base;
        b>>=1;
  }
    return ans;
}

代码短小精悍,但是,我还是不太建议刻意去记它,容易忘。理解之后,自然就记住了。

我们将211211 带入代码走一遍或许你就能够理解了。

其实程序就是自左到右求那三项的值。

211=220221223211=220∗221∗223

上边我们已经知道11的二进制为1011

程序参数a = 2,b =11

ans =1,base = 2

if判断处,11最后一位明显是1,那么我们就需要与结果变量res相乘。

其实,这里的相乘的就是220220 ,乘完之后res = 2.

到第六行代码处,base自乘。这一步我给大家详细解释一下:

base*base = base2base2 ,base2base2=base4base2∗base2=base4 , base4base4=base8base4∗base4=base8 ,base8base8=base16base8∗base8=base16

有没有发现一个问题,每次自乘的结果如下:

base2base4base8base16base32base2、base4、base8、base16、base32

我们换种写法你会更明白:

base21base22base23base24base25base21、base22、base23、base24、base25

你会发现和上边我们要求的一样。

211=220221223211=220∗221∗223

无非是base = 2

b >>= 1右移一位,他的作用是将1011变成101–>10–>1

b的最后一位为0时,不乘base,为1的时候成base。

211=220221223211=220∗221∗223

这样我们能够让res乘上上边的三项,而不乘上2^{2^2}

其实就是根据b的二进制来判断是否乘上二的阶乘。

如果b最后一位为1,也就是说2x2x对b有贡献,所以我们结果乘上base。

否则,我们结果不需要乘base,但是base需要自乘,因为二进制位中左边的权重更大一些。

矩阵快速幂,他的思想和快速幂的思想是一样的。无非就是 底数变为矩阵了。所以你只需定义一下矩阵的乘法即可。

转载于:https://www.cnblogs.com/yjz6/p/9799607.html

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值