快速幂
关于快速幂这一块还是需要做一个总结,写一篇博客捋捋思路,加深理解。
为什么要用快速幂?
例如:现在有一个题目让你求
,你可能觉得很简单啊,来一个for
循环,循环b-1
次就行了。但是如果b非常大的情况下,那这个做法是非常低效的,时间复杂度大致为 O(b)
。
当用快速幂之后,时间复杂度为O(logn)
。
快速幂例子
例如我们用快速幂求 。
将指数拆分能够得到如下的结果。
学过进制转换看到11拆开的样子肯定会很眼熟,其实这里就是跟二进制有关。
11的二进制为1011
,
这样一来,我们求
就不需要算10次了,现在三次就够了。
到这里以后,我们可能会觉得后边的这三项似乎不好求。
不着急,我们先上代码。
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;
}
代码短小精悍,但是,我还是不太建议刻意去记它,容易忘。理解之后,自然就记住了。
我们将 带入代码走一遍或许你就能够理解了。
其实程序就是自左到右求那三项的值。
上边我们已经知道11的二进制为1011
程序参数a = 2,b =11
ans =1,base = 2
到if
判断处,11最后一位明显是1,那么我们就需要与结果变量res
相乘。
其实,这里的相乘的就是
,乘完之后res = 2
.
到第六行代码处,base自乘。这一步我给大家详细解释一下:
base*base = , , ,
有没有发现一个问题,每次自乘的结果如下:
我们换种写法你会更明白:
你会发现和上边我们要求的一样。
无非是base = 2
。
b >>= 1
右移一位,他的作用是将1011
变成101
–>10
–>1
当b
的最后一位为0时,不乘base,为1的时候成base。
这样我们能够让res
乘上上边的三项,而不乘上2^{2^2}
。
其实就是根据b的二进制来判断是否乘上二的阶乘。
如果b最后一位为1
,也就是说
对b有贡献,所以我们结果乘上base。
否则,我们结果不需要乘base,但是base需要自乘,因为二进制位中左边的权重更大一些。
矩阵快速幂,他的思想和快速幂的思想是一样的。无非就是 底数变为矩阵了。所以你只需定义一下矩阵的乘法即可。