345,超级次方
想了解更多数据结构以及算法题,可以关注微信公众号“数据结构和算法”,每天一题为你精彩解答。也可以扫描下面的二维码关注
你的任务是计算 a^b 对 1337 取模,a 是一个正整数,b 是一个非常大的正整数且会以数组形式给出。
示例 1:
输入: a = 2, b = [3]
输出: 8
示例 2:
输入: a = 2, b = [1,0]
输出: 1024
答案:
public int superPow1(int a, int[] b) {
int res = 1;
for (int i : b) {
res = pow(res, 10) * pow(a, i) % 1337;
}
return res;
}
int pow(int x, int y) {
if (y == 0)
return 1;
if (y == 1)
return x % 1337;
return pow(x % 1337, y / 2) * pow(x % 1337, y - y / 2) % 1337;
}
解析:
这题其实更像是一道数学题,要想解这题我们要明白这样一个公式
(a*b)%k=(a%k)*(b%k)%k,很好证明,这里就不在过多解释。上面pow函数使用递归的方式求解x^y,并且每次运算都会对1337求余,举个例子,如果求3^18,我们只需要求3^9然后再相乘即可,如果求3^9,我们只需要求3^4和3^5的乘积即可。代码第4行我们把它想象成一个数组转换为数字这样一个过程,就很容易理解了。下面我们再来看种解法
public int superPow(int a, int[] b) {
int res = 1;
int p = a;
for (int i = b.length - 1; i >= 0; i--) {
res = res * pow(p, b[i], 1337) % 1337;
p = pow(p, 10, 1337);
}
return res;
}
public int pow(int a, int b, int c) {
long res = 1;
long p = a;
while (b > 0) {
if ((b & 1) == 1) {
res = (res * p) % c;
}
p = (p * p) % c;
b >>= 1;
}
return (int) (res % c);
}
函数pow代码很好理解,第15行先判断b是否是奇数,然后再计算。superPow函数中我们首先要明白a^(bc)=(a^b)^c这样一个公式才能看懂上面的代码,比如3^20=(3^10)^2。下面再来看最后一种解法
public int superPow2(int a, int[] b) {
if (a % 1337 == 0)
return 0;
int p = 0;
for (int i : b)
p = (p * 10 + i) % 1140;
if (p == 0)
p += 1440;
return power(a, p, 1337);
}
public int power(int a, int b, int c) {
long res = 1;
long p = a;
while (b > 0) {
if ((b & 1) == 1) {
res = (res * p) % c;
}
p = (p * p) % c;
b >>= 1;
}
return (int) (res % c);
}
这种解法如果看不懂的话,可以忽略。我估计有部分同学是看不懂的,因为这里涉及到一个定理,叫欧拉定理,也叫费马-欧拉定理。下面简单提示一下
1337的因数中除了1和他本身以外,还可以分解为1337=7*191,并且7和191都是质数,也称为素数,φ(7)=6,φ(191)=190,
所以φ(1337)=φ(7)*φ(191)=6*190=1140;
φ(a)表示的是比a小的正整数中与a互素的数的个数。
关注微信公众号“数据结构和算法”,查看更多算法题