快速幂

快速幂

递归快速幂

递归

无非是一个二分的思路。我们很自然地可以得到一个递归方程:

\[a^{n}=\begin{cases} a^{n-1} \cdot a \quad if \ n \ is \ odd\\ a^{ \frac{n}{2}}\cdot a^{ \frac{n}{2}} \quad if \ n \ is \ even\ but\ not\ 0\\ 1 \quad if \ n \ = \ 0\end{cases} \]

计算a的n次方,如果n是偶数(不为0),那么就先计算a的n/2次方,然后平方;如果n是奇数,那么就先计算a的n-1次方,再乘上a;递归出口是a的0次方为1

int qpow(int a, int n)
{
    if (n == 0)
        return 1;
    else if (n & 2 == 1)
        return qpow(a, n - 1) * a;
    else
    {
        int temp = qpow(a, n / 2);
        return temp * temp;
    }
}

在实际问题中,题目常常会要求对一个大数取模,这是因为计算结果可能会非常巨大,但是在这里考察高精度又没有必要。这时我们的快速幂也应当进行取模,此时应当注意,原则是步步取模,如果MOD较大,还应当开long long

static int num;
int qpow(int a, int n)
{
    if (n == 0)
        return 1;
    else if (n & 2 == 1)
        return qpow(a, n - 1) * a%num;
    else
    {
        int temp = qpow(a, n / 2)%num;
        return temp * temp%num;
    }
}

大家知道,递归虽然简洁,但会产生额外的空间开销。我们可以把递归改写为循环,来避免对栈空间的大量占用,也就是非递归快速幂

非递归

我们换一个角度来引入非递归的快速幂。还是7的10次方,但这次,我们把10写成二进制的形式,也就是 \((1010)_{2}\)

现在我们要计算 \(7^{(1010)_{2}}\),可以怎么做?我们很自然地想到可以把它拆分为 \(7^{(1000)_{2}}⋅7^{(10)_{2}}\) 。实际上,对于任意的整数,我们都可以把它拆成若干个 \(7^{(100...)_{2}}\) 的形式相乘。而这些 \(7^{(100...)_{2}}\),恰好就是 \(7^{1}\)\(7^{2}\)\(7^{4}\)……我们只需不断把底数平方就可以算出它们。

//非递归快速幂
static long powMod(long a, int b) {
		long ret = 1;
		while (b != 0) {
			if ((b & 1) == 1)
				ret *= a;
			b >>= 1;
			a = a * a;
		}
		return ret;
	}

这里的位运算符,>>是右移,表示把二进制数往右移一位,相当于/2;

取模版本的

static long powMod(long a, int b, final long mod) {
		long ret = 1;
		while (b != 0) {
			if ((b & 1) == 1)
				ret = ret * a % mod;
			b >>= 1;
			a = a * a % mod;
		}
		return ret % mod;
	}
posted @ 2022-11-25 16:32  QING~h  阅读(51)  评论(0)    收藏  举报