【leedcode】372. 超级次方

193 阅读1分钟

这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战

难度: 中等

题目描述

你的任务是计算 ab 对 1337 取模,a 是一个正整数,b 是一个非常大的正整数且会以数组形式给出。

示例 1:

输入:a = 2, b = [3] 输出:8

示例 2:

输入:a = 2, b = [1,0] 输出:1024

示例 3:

输入:a = 1, b = [4,3,3,8,5,2] 输出:1

示例 4:

输入:a = 2147483647, b = [2,0,0] 输出:1198  

提示:

1 <= a <= 231 - 1 1 <= b.length <= 2000 0 <= b[i] <= 9 b 不含前导 0

解题思路

思路一:

我觉得这个题的难点在于,如何求数组表示的超级大的数字b次幂。原来是求幂也可以做展开,也就是说把前面以求的结果求一次10次幂,然后再去求后面的幂。

注意这里每次计算的结果都要%1337,保留后面的部分。前面被模掉的部分对结果不影响的,所以不用顾虑太多,直接求模。

为了防止数值溢出,我们使用一个小技巧,即(a * b) % k = (a % k) * (b % k) % k

class Solution:
    def pow(self, x: int, n: int) -> int:
        if n < 0:
            return 1 / self.pow(x, -n)
        ans = 1
        while n:
            if n & 1 == 1:
                ans *= x
            x *= x
            n >>= 1
        return ans

    def superPow(self, a: int, b: List[int]) -> int:
       	ans = 1
        mask = 1
        k = 1337
        for num in b[::-1]:
            ans = (ans % k) * (self.pow(a, num * mask) % k) % k
            mask *= 10
        return ans

此题思想是指数数组b的转换。

  • 指数转换:对于a的b次方,b是数组,有a^[1,5,6,4] = a^4 * a^[1, 5, 6, 0] = a^4 * (a^[1, 5, 6])^10。发现问题规模缩小了,可用递归法解。

  • 求模运算:(a * b) % k = (a % k)(b % k) % k,其中a*b可能溢出,用此公式转换后可以避免溢出风险。

另一种求幂运算的高效方法: 对于a^b,有

  1. 如果b是奇数,则a^b = a * a^(b-1);
  2. 如果b是偶数,则a^b = (a^(b/2))^2;
class Solution:
    def superPow(self, a: int, b: List[int]) -> int:
        if not b:
            return 1
        last = b.pop()
        part1 = self.pows(a, last)
        part2 = self.pows(self.superPow(a, b), 10)
        return part1 * part2 % 1337
   

    def pows(self, a, k, base=1337):
        if k == 0:
            return 1
        if k % 2 == 1:
            return (a * self.pows(a, k-1)) % base
        if k % 2 == 0:
            return (self.pows(a, k // 2))**2 % base