leetcode刷题日记- 超级次方

  • 题目描述:
  • 你的任务是计算 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。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lemon_tttea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值