这是我参与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,有
- 如果b是奇数,则a^b = a * a^(b-1);
- 如果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