快速幂

8 篇文章 1 订阅
1 篇文章 0 订阅

以前我看快速幂真的看不懂,但是当我慢慢对递归(递归大法好)有一些理解后,对二分又理解一些后,就能够自己写出快速幂的递归写法了。

求 a^b % m的值,这个用普通算法我就不说了,时间复杂度O(b)

当我知道快速幂之后。才发现 a ^ b还能这样算,太秀了吧,当然你必须带一些二分和递归,不然你看不懂它的递归式。会想(这TM是What ??? )数学之美就是你在能不断刷新你的认知,还TM能这样,太秀了吧,然后你一跺脚,一拍手,就学会了。手动@狗头。

神奇的快速幂,时间复杂度O(logb).

我们已知 2^3  求 2^6,不就是 2^3 * 2^3嘛。快速幂就是这个原理。

那有同学问了遇到奇数怎么办?2 ^ 5??

那不就是 2 * 2 ^ 4 这不就成了嘛。

所以这就是快速幂的基本思路求a ^ b

1)当b是奇数时,那么有 a^b = a * a^*(b-1)

2)当b是偶数时,那么有 a^b = a^(b/2) * a^(b/2)

举个例子?2 ^10

  1. 2^10 = 2^5 * 2^5
  2. 2^5 = 2 * 2^4
  3. 2^4 = 2^2 * 2^2
  4. 2^2 = 2^1 * 2^1
  5. 2^1 = 2 * 2^0

根据这两个条件写递归式嘛,这还不简单?

typedef long long ll;
ll binaryPow(ll a, ll b, ll m){
	if(b == 0)
		return 1;
	else if(b % 2 == 1)
		return a * binaryPow(a, b - 1, m) % m;
	else{
		ll num = binaryPow(a, b/2, m) % m;	//优化 
		return num * num % m;// 不直接写成return binaryPow(a, b/2, m) * binaryPow(a, b/2, m)
	}
	
}

上述

if(b % 2 == 1)
可以改为
if(b & 1)

因为b & 1 是按位与,判断b的末尾是否为1 ,因此当b 为奇数时 b & 1 返回为1,if条件成立,这样执行速度更快

+-一般使用2个CPU时钟
位运算 只要1个
* 要4个
/ 要40个

那我们是不是要学习一下位运算:位运算

针对不同的题目,有两个细节需要注意

1)如果初始值a 大于 m ,那么需要在进入函数前就让a 对 m 取模,

2)若果m 为 1,可以直接在函数外部特判为 0,不需要进入函数来计算。(因为任何数对1 取模都是0。

快速幂的迭代写法

研究一下快速幂的迭代写法。

对于 a ^ b来说,若果把 b 写成2 进制,那么b 就可以写成若干二次幂之和,如13 的二进制 1101,于是3 号位 、2号位、0号位就都是1,那么就可以得到13 = 2^3 + 2^2 + 2^1 = 8 + 4 + 1。所以a ^13 = a^8 * a^4 * a^1。

通过同样的推导,我们可以把任意的a^b 表示成 a^(2^k)……、a^8、a^4、a^2、a^1中若干的乘积。若果二进制的i号位为1.那么想中的a^(2^i)就被选中。于是可以得到计算a^b的大致思路:令i 从0到k枚举b的二进制的每一位,如果为1 那就累计a^(2^i)。注意

a^(2^k)……、a^8、a^4、a^2、a^1前一项总是等于后一项的平方。具体步骤。

(1)初始令ans = 1,用来存放累积的结果。

(2)判断b的二进制末尾是否为1 ,(及判断 b&1 是否为 1),也可以理解为判断b 是否为奇数。如果是的话,令ans乘上a的值。

(3)令a平方,并使b右移一位,(也可以理解为,b/2)

(4)只要b 大于0,就返回(2)。

typedef long long ll
ll binaryPow(ll a, ll b, ll m){
	ll ans = 1;
	while(b > 0){
		if(b & 1){
			ans = ans * a % m;
		}
		a = a * a % m;
		b >>= 1; 
	} 
	return ans;
}

 例:a^13

bb&1ansa
  1a
110111*a=aa^2
1100aa^4
111a*a^4 = a^5a^8
11a^5 * a^8 = a ^ 13 

总结

我认为递归更好记,迭代还可以,但是我们知道了 我们需要补习一下位运算。

咦,递归和2分好像啊。。。。递归如果以中间作为中点递归,感觉就是二分的一种。

 

  • 65
    点赞
  • 153
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值