快速幂


超级详细的基础算法和数据结构合集:
https://blog.csdn.net/GD_ONE/article/details/104061907

摘要

本文主要介绍快速幂算法,快速幂虽然代码简单,但是往往会与其他算法相结合,很重要。

引言

当我们计算 n k n^k nk时,常用的做法是对 n n n连乘 k k k次, 但如果 k k k特别大,假如 k = 1 e 6 k = 1e6 k=1e6, 如果仍然对 n 连 乘 1 e 6 n连乘1e6 n1e6次的话,时间消耗就太大了。那么我们如何
在短时间内求出一个数的 k k k次方呢。

n k n^k nk

我们可以考虑对朴素方法进行优化。
1:当我们计算得到 n 2 n^2 n2时, 我们可以直接使用 n 2 n^2 n2连乘 k / 2 k/2 k/2次。 这样做时间复杂度变为了 O ( n / 2 ) O(n/2) O(n/2)
2:有人可能会问,我们既然可以用 n 2 连 乘 k / 2 n^2连乘k/2 n2k/2次,为什么不用 n 4 n^4 n4连乘 k / 4 k/4 k/4次呢,当然可以这样做之后时间复杂度变为了 O ( n / 4 ) O(n/4) O(n/4);
3 : 我们当然也可以 n 8 , n 16 . . . 连 乘 n^8,n^{16}...连乘 n8,n16...
4:所以我们可以用: n 1 ∗ n 2 ∗ n 4 ∗ n 8 . . . n p n^1 * n^2 * n^ 4 *n^8...n^p n1n2n4n8...np
快速幂就是类似的思想。

快速幂

先举个例子:
3 11 = 3 1 ∗ 3 1 ∗ 3 1 ∗ 3 1 ∗ 3 1 ∗ 3 1 ∗ 3 1 ∗ 3 1 ∗ 3 1 ∗ 3 1 ∗ 3 1 3^{11} = 3^1* 3^1 *3^1*3^1*3^1*3^1*3^1*3^1*3^1*3^1*3^1 311=3131313131313131313131
11 的 二 进 制 表 示 为 : 1011 11的二进制表示为: 1011 111011
怎么把一个二进制数转化为十进制数呢?
计算过程是: 11 = 1 ∗ 2 0 + 1 ∗ 2 1 + 0 ∗ 2 2 + 1 ∗ 2 3 = 1 + 2 + 0 + 8 11 = 1*2^0 + 1 * 2^1 + 0 * 2^2+ 1*2^3 = 1 + 2 + 0 + 8 11=120+121+022+123=1+2+0+8
我们可以发现:如果将最开始求 3 11 3^{11} 311变为: 3 11 = 3 1 ∗ 3 2 ∗ 3 0 ∗ 3 8 3^{11} = 3^1 * 3^2 * 3^0*3^8 311=31323038, 计算量将会大大减少,原本需要乘11次,现在只需要乘4次。

另外,我们需要判断二进制数的某一位是不是0,我们可以使用位运算方便的解决该问题。

快速幂代码:

public static int qmi(int a, int b){ //求 a^b
	int res = 1; // res保存结果
	while(b != 0){
		if((b & 1) == 1){ //如果k的二进制数的最后一位是 1。 比如1011 & 1 = 1
			res = (res * a) % mod;//取模, 防止结果溢出。
		}
		a = a * a % mod;//得到 a^1, a^2, a^4, a^8, .....
		b = b >> 1; //将b右移一位,去掉最低位。为了开始判断下一位。
	}
	return res;
}

代码很简单,多看几遍就懂了。如果对位运算不熟悉可以翻看之前的博客。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值