快速幂取模

先上代码


   public static long process(long a, long x, final long mod) {
       return x == 1 ? a :
               process(a * a % mod, x >> 1, mod) * ((x & 1) == 0 ? 1 : a) % mod;
    }

没错,上面就是全部的代码了,就一行,是不是感觉很神奇。

1. 什么是快速幂取模?

刚开始接触的时候听名字感觉很高大上的东西,后来发现就是算 a n m o d    c a^n \mod c anmodc的一个东西。只不过时间复杂度是 O ( l o g n ) O(logn) O(logn)级别的。比普通的 O ( n ) O(n) O(n)快点而已。

2. 算法核心是什么?

算法的核心思想很简单,就是我们平常用的东西。

比如算 2 8 2^8 28 = 2 ∗ 2 ∗ 2 ∗ 2... = 4 ∗ 4 ∗ 4 ∗ 4 = 16 ∗ 16 2 * 2 * 2 * 2 ...= 4 * 4 * 4 * 4 = 16 * 16 2222...=4444=1616。这个就是快速幂,也就是说如果算 2 8 2^8 28本来是需要算7次 2 ∗ 2 2 * 2 22的,现在只需要算3次 4 ∗ 4 4 *4 44或者一次 16 ∗ 16 16 * 16 1616就能解决了。也就是说 2 8 = ( 2 2 ) 8 / 2 = ( 4 ) 4 = ( 4 2 ) 4 / 2 = ( 16 ) 2 2^8 = (2^2)^{8/2} =(4)^4=(4^2)^{4/2}=(16)^2 28=(22)8/2=(4)4=(42)4/2=(16)2

3. 怎么描述这个过程呢?

采用递归的方式很容易表达这个过程。
q u i c k P o w ( 2 , 8 ) = q u i c k P o w ( 2 2 , 4 / 2 ) = q u i c k P o w ( 4 , 4 ) quickPow(2, 8) = quickPow(2 ^ 2, 4 / 2) = quickPow(4, 4) quickPow(2,8)=quickPow(22,4/2)=quickPow(4,4)
q u i c k P o w ( 4 , 4 ) = q u i c k P o w ( 4 2 , 4 / 2 ) = q u i c k P o w ( 16 , 2 ) quickPow(4, 4) = quickPow(4 ^ 2, 4 / 2) = quickPow(16,2) quickPow(4,4)=quickPow(42,4/2)=quickPow(16,2)

也就是说
q u i c k P o w ( a , b ) = q u i c k P o w ( a 2 , b / 2 ) quickPow(a, b) = quickPow(a^2, b / 2) quickPow(a,b)=quickPow(a2,b/2)

4. 上面过程有什么问题吗?

没错,上面过程确实有问题。上面只考虑了b是2的整数倍的情况,对于 2 3 2^3 23
这种情况是不管用的。因为pow(2, 3) != pow(4, 1)。那么怎么改正呢?
不难发现,如果是奇数的话,那么a最多剩下一个。所以如果b是奇数的情况下,只要在多乘以一个a就可以解决了。也就是pow(2,3) = pow(2,2) * 2

也就是说,如果 b m o d    2 = = 1 b\mod 2 == 1 bmod2==1
p o w ( a , b ) = p o w ( a 2 , b / 2 ) ∗ a pow(a,b) = pow(a ^ 2, b / 2) * a pow(a,b)=pow(a2,b/2)a

5. 取模的含义是啥呢?

当时一直以为快速幂取模,是关于取模的高阶操作,后来发现取模就是凑数用的。快速幂取模,重点是快速幂。取模纯属因为计算机表达不了这么大的数字而已。取模用到了一个性质 a ∗ b m o d    c = ( a m o d    c ) ∗ ( b m o d    c ) m o d    c a*b \mod c = (a \mod c) * (b \mod c) \mod c abmodc=(amodc)(bmodc)modc

用到快速幂里面就是对每一个乘法加上一个取模,防止溢出就行了。

  • b为奇数的情况下

q u i c k P o w ( a , b ) = q u i c k P o w ( a 2 m o d    c , b / 2 ) ∗ a m o d    c quickPow(a, b) = quickPow(a^2\mod c, b/2) * a \mod c quickPow(a,b)=quickPow(a2modc,b/2)amodc

  • b为偶数的情况下

q u i c k P o w ( a , b ) = q u i c k P o w ( a 2 m o d    c , b / 2 ) m o d    c quickPow(a, b) = quickPow(a^2\mod c, b/2) \mod c quickPow(a,b)=quickPow(a2modc,b/2)modc

看到这就知道,最上面的那行代码是什么意思了吧。也就是用 O ( l o g n ) O(logn) O(logn)的时间复杂度求 a n m o d    c a^n \mod c anmodc

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值