首先对于幂和取模想必大家都不是很陌生,幂即一个数的多少次方,取模即取余运算:
下面咱们进行一个数的幂取模运算的最容易想到的方式:
a//底数
b//幂指数
c//取模数
//算法一:
int ans=1;
for(int t=1;t<=b;t++)
{
ans=ans*a;
}
return ans%c;
时间复杂度为O(b),以上算法存在很大的一个问题在于多次求幂指数之后会超过整数类型的范围, 这是个很麻烦的问题
但是我们在离散数学或者数论中曾接触到这样一个定理或者公式
由此可以想到刚才的另一种求的算法
//算法二:
int ans=1;
int a=a%c;
for(int t=1;t<=b;t++)
{
ans=ans*a
}
return ans%c
既然a的求幂过程中可以先转化成a%c,那我们不难想到在循环ans时也可以%c从而控制数的大小
//算法三:
int ans=1;
int a=a%c;
for(int t=1;t<=b;t++)
{
ans=(ans*a)%c;
}
return ans%c;
数字超出整型范围的问题几本解决了 ,那我们能不能去降低O(b)的时间复杂度呢
答案是肯定的:
我们可以根据b来进行一定量的缩减:
如果b是偶数,我们有如下公式
同理奇数的公式也能相应的得到
这时,我们将a^2看做是一个变量k;
于是有了下面的代码
//算法4:
int ans=1;
int k;
a=a%c;
for(int t=1;t<=b/2;t++)
{
k=(a*a)%c;
ans=(ans*k)%c;
}
if(b%2==1)
return (ans*a%c)%c;
else
return ans%c;
此时我们的时间复杂度已经降到了O(b/2)
那我们还能不能再提高一下呢
答案依然是肯定的:
这是反复循环利用了算法四的思想
//算法5:
//已经成为一个函数
int quickpower(int x,int y,int z)
{
int ans=1;
x=x%z;
while(y>0)
{
if(y%2==1)
{
ans=(ans*x)%z;
}
y/=2;
x=x*x%z;
}
return ans;
}
时间复杂度为O(logb)一般情况基本不超时,
还请大佬多多交流——————QQ656484427