前言
回国了,开始好好准备找工。
本周主题:快速幂
题目:
- 240730每日一题—Double Modular Exponentiation
快速幂
「快速幂算法」的本质是分治算法。举个例子,如果我们要计算 x64 ,我们可以按照:
x→x2→x4→x8→x16→x32→x64的顺序,从 x 开始,每次直接把上一次的结果进行平方,计算 6 次就可以得到 x64 的值,而不需要对 x 乘 63 次 x 。
再举一个例子,如果我们要计算 x77 ,我们可以按照:
x→x2→x4→x9→x19→x38→x77的顺序, 在 x→x2,x2→x4,x19→x38 这些步骤中, 我们直接把上一次的结果进行平方,而在 x4→x9,x9→x19,x38→x77 这些步骤中,我们把上一次的结果进行平方后,还要额外乘一个 x 。
直接从左到右进行推导看上去很困难,因为在每一步中,我们不知道在将上一次的结果平方之后, 还需不需要额外乘 x 。但如果我们从右往左看, 分治的思想就十分明显了:
- 当我们要计算 xn 时,我们可以先递归地计算出 y=x⌊n/2⌋ ,其中 ⌊a⌋表示对 a 进行下取整;
- 根据递归计算的结果, 如果 n 为偶数, 那么 xn=y2; 如果 n 为奇数,那么 xn=y2×x ;
- 递归的边界为 n=0, 任意数的 0 次方均为 1 。
由于每次递归都会使得指数减少一半,因此递归的层数为 O(logn),算法可以在很快的时间内得到结果。
下面是快速幂算法的递归实现:
1 | class Solution { |
进一步,由于递归需要使用额外的栈空间,我们试着将递归转写为迭代。我们还是以 x77 作为例子:
x→x2→x4→+x9→+x19→x38→+x77并且把需要额外乘 x 的步骤打上了 + 标记。可以发现:
- x38→+x77 中额外乘的 x 在 x77 中贡献了 x ;
- x9→+x19 中额外乘的 x 在之后被平方了 2 次,因此在 x77 中贡献了 x22=x4
- x4→+x9 中额外乘的 x 在之后被平方了 3 次,因此在 x77 中贡献了 x23=x8
- 最初的 x 在之后被平方了 6 次,因此在 x77 中贡献了 x26=x64 。
我们把这些贡献相乘, x×x4×x8×x64 恰好等于 x77 。而这些贡献的指数部分又是什么呢?它们都是 2 的幂次,这是因为每个额外乘的 x 在之后都会被平方若干次。而这些指数 1,4,8 和 64, 恰好就对应了 77 的二进制表示 (1001101)2 中的每个 1 !
因此我们借助整数的二进制拆分,就可以得到迭代计算的方法,一般地,如果整数 n 的二进制拆分为
n=2i0+2i1+⋯+2ik那么
xn=x2i0×x2i1×⋯×x2ik这样以来, 我们从 x 开始不断地进行平方, 得到 x2,x4,x8,x16,⋯, 如果 n的第 k 个(从右往左,从 0 开始计数)二进制位为 1 ,那么我们就将对应的贡献 x2k 计入答案。
下面是快速幂的迭代实现:
1 | class Solution { |
例题:Double Modular Exponentiation
Double Modular Exponentiation
You are given a 0-indexed 2D array variables where variables[i] = [ai, bi, ci, mi], and an integer target.
An index i is good if the following formula holds:
- 0 <= i < variables.length
- ((ai^bi % 10)^ci) % mi == target
Return an array consisting of good indices in any order.
计算式中重复出现的模式是“幂+取模”,于是可以把快速幂和取模融合在一起。
另一个知识点是“加法和乘法”的取模,有如下公式:
(a+b)modm=((amodm)+(bmodm))modm (a⋅b)modm=((amodm)⋅(bmodm))modm
因此我们可以在计算过程中(例如循环),对加法和乘法的结果取模,而不是在循环结束后再取模。
更多模相关的内容请看:https://leetcode.cn/circle/discuss/mDfnkW/
1 | class Solution { |
参考文献
[1] https://leetcode.cn/circle/discuss/mDfnkW/
[2] https://leetcode.cn/problems/powx-n/solutions/238559/powx-n-by-leetcode-solution/
后记
首发于 silencezheng.top,转载请注明出处。