快速幂应用
快速幂,也称平方求幂,可以在O(nlogn)时间复杂度内计算乘方,在许多算法中如大数求余中被广泛应用。
问题引出
如计算7的10次方,怎么算比较快?
普遍的想法是10个7一直乘下去,共执行9次乘法运算。这样是比较慢的,而且也没发挥出cpu的高性能计算。
于是,我们可以进行一个拆分操作。先7×7=49,然后7的5次方49×49×7=16807,再然后7的5次方乘7的5次方,计算得到7的10次方。
算法思路
以上可概述为一个二分的思想,并且得到一个递归方程:

代码实现
原理代码
1 2 3 4 5 6 7 8 9 10 11 12 13
| int quick_pow(int a, int n) { if (n == 0) return 1; else if (n % 2 == 1) return quick_pow(a, n - 1) * a; else { int temp = quick_pow(a, n / 2); return temp * temp; } }
|
注意,这个temp变量是必要的,因为如果不把
记录下来,直接写成quick_pow(a, n /2)*quick_pow(a, n /2),那会计算两次
,整个算法就退化为了
。
快速幂模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public double myPow(double x, int n) { double ans = 1, temp = x; int exp = n; while (exp != 0) { if ((exp % 2) != 0) { ans = ans * temp; } temp = temp * temp; exp /= 2; } return n > 0 ? ans : 1 / ans; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Solution { public: double myPow(double x, int n) { double res=1.0; int i=n; while(i){ if(i&1)res*=x; x*=x; i/=2; } return n<0?1/res:res; } };
|
实际应用
在实际问题中,题目常常会要求对一个大素数取模(%1000000007),这是因为计算结果可能会非常巨大,但是在这里考察高精度又没有必要。这时我们的快速幂也应当进行取模,此时应当注意,原则是步步取模,如果MOD较大,还应当开long long。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #define MOD 1000000007 typedef long long ll; ll qpow(ll a, ll n) { if (n == 0) return 1; else if (n % 2 == 1) return qpow(a, n - 1) * a % MOD; else { ll temp = qpow(a, n / 2) % MOD; return temp * temp % MOD; } }
|
例题
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m] 。请问 k[0]k[1]…*k[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { public int cuttingRope(int n) { if(n <= 3) return n - 1; int b = n % 3, p = 1000000007; long rem = 1, x = 3; for(int a = n / 3 - 1; a > 0; a /= 2) { if(a % 2 == 1) rem = (rem * x) % p; x = (x * x) % p; } if(b == 0) return (int)(rem * 3 % p); if(b == 1) return (int)(rem * 4 % p); return (int)(rem * 6 % p); } }
|