- 题目描述:
-
你的任务是计算 ab 对 1337 取模,a 是一个正整数,b 是一个非常大的正整数且会以数组形式给出
- 示例
-
输入:a = 2, b = [3]
输出:8
输入:a = 2147483647, b = [2,0,0]
输出:1198 - 解析:这是一个看起来很简单,实质上很复杂的题目,前提是如果你知道余数定理和快速幂的话,如果不知道这就是一个很难的题目了。再将余数定理之前,先说一下快速幂,这题就是快速幂+余数定理的结合。
- 先说说快速幂的问题,讲快速幂之前先说一说分治的思想。比如我们要算5234的值,如果我们直接算234个5相乘,计算次数是很多的,是235次,但是我们可以采用分治的思想,比如234可以拆解成2100+310+4,那么5234=52*100+3*10+4=52*100*53*10*54,这样幂的次数就降低了很多,关于原来的式子还可以进一步分治,将每次的幂分解为10以内的式子,如52*100= ((52)10)10,以此类推,从而将每个幂将为10以内的数字,来减少运算次数,分治之后我们的计算次数为3+2+1=6次,可见运算次数大大减少。实际中的快速幂为了方便运算,采用了更为简单的二分思路。即如果我还是要算5234,计算过程如下
-
5234=5234/2*5234/2=5117*5117
5117=5117-1*5 (117为基数,因此要拆解为an=an-1*a)
5116=5116/2* 5116/2
…以此类推 - 到这里就很明显了,实际中的快速幂大多采用递归的方式进行运算,将O(n)的时间复杂度降低为了O(log n)的时间复杂度。
- 余数定理主要有三个
-
1-余数的加法定理:a与b的和除以c的余数,等于a,b分别除以c的余数之和,或这个和除以c的余数(如果余数之和大于c),即(a+b)%c = (a%c+b%c)%c。
-
2-余数的乘法定理:a与b的乘积除以c的余数,等于a,b分别除以c的余数的积,或者这个积除以c所得的余数(如果余数之积大于c),即(a*b)%c = (a%c*b%c)%c,这里有一个特例,如果a=b,那么(a*b)%c =((a%c)2)%c,假设a%b=c那么,就有(am)%b=(cm)%b,这个公式就是解决这道题的关键。
-
若两个数a,b除以同一个数m得到的余数相同,则a,b的差一定能被m整除。这个就简单提一下,本题用不到。
- 代码如下:
class Solution:
def superPow(self, a: int, b: List[int]) -> int:
"""
计算a的b次幂对1337取模,b以数组的形式给出
>>>self.superPow(2, [1, 0])
>>>1024
"""
res = 1
for i in b:
res = res%1337
res = (res**10)*(a**i)
return res%1337
- 代码解读,本例用了快速幂的思想和余数定理的第二条,再每一次对res进行整体幂运算的时候对res进行取余,因为res%1337等价于(res10)%1337。