快速幂算法的目的,就是快速计算 x 的 n 次方。基本思路是把 n 视作二进制数,则 n 可以被分解为多个 2 的幂次方之和,如 12 对应 1100 等于 0 ∗ 2 0 + 0 ∗ 2 1 + 1 ∗ 2 2 + 1 ∗ 2 3 0*{2^0} + 0*{2^1} + 1*{2^2} + 1*{2^3} 0∗20+0∗21+1∗22+1∗23,即二进制数中每一位的0或1对应的正是系数。因此, x 12 = x 0 ∗ 2 0 + x 0 ∗ 2 1 + x 1 ∗ 2 2 + x 1 ∗ 2 3 {x^{12}} = {x^{0*{2^0}}} + {x^{0*{2^1}}} + {x^{1*{2^2}}} + {x^{1*{2^3}}} x12=x0∗20+x0∗21+x1∗22+x1∗23。从 n 的二进制形式可以得到系数,而对应的 x 的二次幂可以通过 x 自乘得到( x = x 2 0 , x ∗ x = x 2 1 , x 2 ∗ x 2 = x 2 2 . . . . . . x = {x^{{2^0}}},x*x = {x^{{2^1}}},{x^2}*{x^2} = {x^{{2^2}}}...... x=x20,x∗x=x21,x2∗x2=x22......)。实现上可以使用递归或者迭代,迭代的空间复杂度更优:
递归法:
class Solution:
def myPow(self, x: float, n: int) -> float:
def quickMul(N: int):
if N == 0:
return 1.0
y = quickMul(N // 2)
return y * y if N % 2 == 0 else y * y * x
return quickMul(n) if n >= 0 else 1.0 / quickMul(-n)
迭代法:
class Solution:
def myPow(self, x: float, n: int) -> float:
if x == 0.0:
return 0.0
ans = 1
if n < 0:
x = 1 / x
n = -n
while n:
if n & 1:
ans *= x
x *= x
n >>= 1
return ans
做这题需要知道的公式是: ( a ∗ b ) % M O D = ( ( a % M O D ) ∗ ( b % M O D ) ) % M O D (a*b)\% MOD = ((a\% MOD)*(b\% MOD))\% MOD (a∗b)%MOD=((a%MOD)∗(b%MOD))%MOD
class Solution:
# 快速幂算法
def quick_mul(self, x: int, n: int) -> int:
MOD = 1337
ans = 1
while n:
if n & 1:
ans = ans * x % MOD
x = x * x % MOD
n >>= 1
return ans
def superPow(self, a: int, b: List[int]) -> int:
MOD = 1337
ans = 1
x = a % MOD
for y in b[::-1]:
ans = ans * self.quick_mul(x, y) % MOD
x = self.quick_mul(x, 10)
return ans
关键是两点:一是根据公式,增加了多次取模操作(MOD);二是由于指数存储在了数组中,从右到左遍历是低位到高位,两种方法,一是用一个变量记录当前是第几位,则从数组取出来的数与 10 的多少次方相乘,二是每次将底数 x 乘以 10 次方,这样也相当于指数乘以 10,例如 x 123 = ( x 1 ) 3 + ( x 10 ) 2 + ( x 100 ) 1 {x^{123}} = {({x^1})^3} + {({x^{10}})^2} + {({x^{100}})^1} x123=(x1)3+(x10)2+(x100)1。