快速幂算法(例:a^b mod p)
介绍
快速幂(Exponentiation by squaring,平方求幂)是一种简单而有效的小算法,它可以以O(log n)的时间复杂度计算乘方。快速幂不仅本身非常常见,而且后续很多算法也都会用到快速幂。
为什么要使用快速幂?
比如要计算以下式子:
传统算法是
计算机要通过9次计算才能得出答案。而快速幂的方法就是通过平方来减少计算次数:
这样子就只需要4次。
这样的时间复杂度是O(log n),当次方很大时可以节省很多时间。
算法实现
非递归版
1 | fast_power(a, b) |
在b % 2 == 1运行完成后,b必定是偶数,接下来会再次进行while循环进入到else里面,其实我们可以简化成一次循环,如下:
1 | fast_power(a, b) |
递归版(慎用)
1 | fast_power(a, b) |
以上都要注意变量a, b, ans的范围。
例题a^b
题目:牛客网
输入描述:
三个用空格隔开的整数a,b和p。
输出描述:
一个整数,表示a^b mod p的值。
思路:
最直接的思路就是算出a^b的值之后再模p,不管是否上述快速幂的方法,都存在一个很明显问题是 a^b 的范围大至10的9次方的10的9次方,远超过了long long的范围。
利用快速幂+取模运算的性质,可以快速的同时不会让数值超过范围,性质(a b) % p = (a % p b % p) % p
于是可以得到以下代码:
1
2
3
4
5
6
7
8
9
10
11
12typedef long long ll;
ll fast_power(ll a, ll b, ll p) {
ll ans = 1;
a %= p;
while(b) {
if(b % 2 == 1)
ans = (ans * a) % p;
a = (a * a) % p;
b /= 2;
}
return ans % p;
}其实还可以使用位运算,提升运行的速度,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12typedef long long ll;
ll fast_power(ll a, ll b, ll p) {
ll ans = 1;
a %= p;
while(b) {
if(b & 1) // 如7二进制为0000 0111,1二进制为0000 0001,则7&1 = 0000 0001 = 1
ans = (ans * a) % p;
a = (a * a) % p;
b >>= 1; // 7二进制为0000 0111,向右位移一位为 0000 0011 = 3 (不足补0)
}
return ans % p;
}常见的位运算符有 与& 或| 右移>> 左移<< 异或^
最终代码:
1 |
|
参考资料:
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Wshape1's Blogs!
评论