原题
372.超级次方
——————————————————————————————————————
我做的第一道中等难度的题
题解
方法一
指数二分降幂。
本思路java代码示例:
/*
*@v7fgg
*执行用时:10 ms, 在所有 Java 提交中击败了53.28%的用户
*内存消耗:39.9 MB, 在所有 Java 提交中击败了100.00%的用户
*2020年6月24日 12:08
*/
class Solution {
public int superPow(int a, int[] b) {
int ans=1;
a%=1337;
for(int i=0;i<b.length;i++){
ans=cifang(ans,10)*cifang(a,b[i])%1337;
}
return ans;
}
public int cifang(int a,int p){
//计算a的p次方模1337的值,p不大于10
if(p==0){return 1;}
if(p==1){return a;}
return cifang(a,p/2)*cifang(a,p-p/2)%1337;
}
}
方法二 利用欧拉函数以及大数降幂取模
(也是看过了并参考别人的思路后):
1、首先借助[欧拉函数]
(https://baike.baidu.com/item/%E6%AC%A7%E6%8B%89%E5%87%BD%E6%95%B0/1944850?fr=aladdin),算出作为模的底的1337有多少个小于它与之互质的正整数,即求出φ(1337)=1140,这个数的计算方法在其他人解答中多体现乘代码形式,而后带入1337再求出,我这里是走了一个小小的捷径,直接求出为1140;
2、就是下图的公式了
这里把原本以数组形式表示的超大的指数B,代码中用numB逐位取模的方法来大大减小其值,最后循环了新numB次求出题解
本思路代码示例:
java:
class Solution {
public int superPow(int a, int[] b) {
int numB=b[0];
a=a%1337;
if(a==0){
return 0;
}
for(int i=1;i<b.length;i++){
numB=(numB*10+b[i])%1140;
//numB*=10;
}
numB+=1140;
int x=a;
for(int j=0;j<numB;j++){
x=x%1337;
x*=a;
}x/=a;
return x;
}
}
java运行后时空利用:
python:
class Solution:
def superPow(self, a: int, b: List[int]) -> int:
a=a%1337
bs=b[0]
x=a
if(a==0):
return 0
for i in range(1, len(b)):
bs=(bs*10+b[i])%1140
bs+=1140
for j in range(0,bs):
x=(x%1337)*a
return int(x/a)
c++
class Solution {
public:
int superPow(int a, vector<int>& b) {
int numB=b[0];
a=a%1337;
if(a==0){
return 0;
}
for(int i=1;i<b.size();i++){
numB=(numB*10+b[i])%1140;
}
numB+=1140;
int x=a;
for(int j=0;j<numB;j++){
x=x%1337;
x*=a;
}x/=a;
return x;
}
};
另外强调一点错误的想法,本题中讲的是超级大的指数,而一般的long类型里面最大的也只有64位,倘若b数组给出长度成千上万,就远远不是计算机所能处理的了,所以在处理指数的时候,不能妄想把b数组一逐位乘10再加下一位的方法来得到这个指数,那是不可能的,因此才引进了降幂同余公式。一下是错误的java实例:
class Solution {
public int superPow(int a, int[] b) {
int numB=0;
a=a%1337;
if(a==0){
return 0;
}
for(int i=0;i<b.length;i++){//b数组超长时在这里会报错越界
numB+=b[i];
numB*=10;
}
numB/=10;
int x=a;
for(int j=0;j<numB;j++){
x=x%1337;
x*=a;
}x/=a;
return x;
}
}