快速幂算法

204 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

快速幂

当我们需要计算2^100000000^的时候,不断while循环,会使用大量的时间。因此快速幂算法出来了。简单通俗点来讲,快速幂就是将底数变得越大,指数变得越小。最终我们会得到O(log n)计算幂运算的算法

话不多说,先上代码

typedef lond lond ll;
ll mod_pow(ll x,ll n,ll mod){
	ll res=1;
	while(n>0){
		if(n&1)  res=res*x%mod;
		x=x*x%mod;
		n>>=1;
	}
	return res;
}

快速幂的讲解

首先普及下模运算的基础运算

(a + b) % p = (a % p + b % p) % p (1) (a - b) % p = (a % p - b % p ) % p (2) (a * b) % p = (a % p * b % p) % p (3)

其中我们只要关注第“3”条法则即可:(a * b) % p = (a % p * b % p) % p ,我们仔细研究一下这个运算法则,会发现多个因子连续的乘积取模的结果等于每个因子取模后的乘积再取模的结果。也就是说,我们如果要求: (abc)%d=(a%db%dc%d)%d;

重点:

快速幂和核心思想是底数变大,指数变小

310=33333333333^{10}=3*3*3*3*3*3*3*3*3*3

可以这样转换:

310=(33)5=9491=81291=65619=590493^{10}=(3*3)^5 =9^4*9^1 =81^2*9^1=6561*9=59049

按照指数的情况应该分为偶数、奇数两种 代码如下:

long long fastPower(long long base, long long power,long long mod) {
    long long result = 1;
    while (power > 0) {
        if (power % 2 == 0) {
            //如果指数为偶数
            power = power / 2;//把指数缩小为一半
            base = base * base % mod;//底数变大成原来的平方
        } else {
            //如果指数为奇数
            power = power - 1;//把指数减去1,使其变成一个偶数
            result = result * base % mod;//此时记得要把指数为奇数时分离出来的底数的一次方收集好
            power = power / 2;//此时指数为偶数,可以继续执行操作
            base = base * base % mod;
        }
    }
    return result;
}

n&1等价于n转换为二进制然后判断最低位是否为1.如果为1就是奇数,如果为0就是偶数。 压榨性能再优化 最终代码为:

typedef lond lond ll;
ll mod_pow(ll x,ll n,ll mod){
	ll res=1;
	while(n>0){
		if(n&1)  res=res*x%mod;
		x=x*x%mod;
		n>>=1;
	}
	return res;
}

也可以采用递归的思想:

typedef lond lond ll;
ll mod_pow(ll x,ll n,ll mod){
	if(n==0)  return 1;
	ll res=mod_pow(x*x%mod,n/2,mod);
	if(n&1)	res=res*x%mod;
	return res;
}

借鉴 快速幂算法——带你从零开始一步一步优化 这篇文章可以让你理解的更深!!!