C++快速幂详解


快速幂

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

为什么要用快速幂?

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

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

快速幂例子

例如我们用快速幂求 2 11

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

2 11 = 2 2 0 + 2 1 + 2 3

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

11的二进制为1011 , 11 = 2 3 1 + 2 2 0 + 2 1 1 + 2 0 1

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

2 11 = 2 2 0 2 2 1 2 2 3

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

不着急,我们先上代码。

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;
}

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

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

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

2 11 = 2 2 0 2 2 1 2 2 3

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

程序参数a = 2,b =11

ans =1,base = 2

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

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

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

base*base = b a s e 2 , b a s e 2 b a s e 2 = b a s e 4 , b a s e 4 b a s e 4 = b a s e 8 , b a s e 8 b a s e 8 = b a s e 16

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

b a s e 2 b a s e 4 b a s e 8 b a s e 16 b a s e 32

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

b a s e 2 1 b a s e 2 2 b a s e 2 3 b a s e 2 4 b a s e 2 5

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

2 11 = 2 2 0 2 2 1 2 2 3

无非是base = 2

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

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

2 11 = 2 2 0 2 2 1 2 2 3

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

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

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

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

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


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM