目录
快速幂
顾名思义,快速幂就是快速计算底数的n次幂。它的时间复杂度为,而直接用for循环一次次计算的时间复杂度为。
原理
通过将指数拆分成几个因数相乘的形式,来简化幂运算。具体就是每一步都把指数分成两半(在可分的情况下),而相应的底数做平方运算。这样不仅能把非常大的指数给不断变小,还能节省计算机计算所消耗的时间。下面我们看个简单的例子。
例子
计算: ———— ①
用一般的for循环计算这个值得话需要循环10次才能计算出结果,但如果我们进行一下处理:
//此时它的指数由10降低为5,则连带上一次运算,我们的计算次数就变为6次了
这样处理的话在进行比较大的幂运算时会节省很多时间,比如说计算时,底数先进行一个平方运算就能把指数由100000变为50000,节省了50000次for循环的时间。
我们再接着处理,这是后我们发现5不能被分成两半了,因为5是奇数。
但我们可以把它处理为这样:,这样我们又可以接着对进行分半:,此时式子①就可以表示为。此时计算次数由6变为了5我们接着进行分半工作直到指数都为1。最后①变为:。
这样如果用计算机计算幂很大的数时就可以快速幂算法简化计算,加快运算时间。
算法实现
//快速幂函数
long long fastPower(long long base, long long power) {
long long result = 1; //result记录算出的结果
while (power > 0) { //指数变为1时停止
//如果指数power为偶数
if (power % 2 == 0) {
power = power / 2; //把指数缩小为一半
base = base * base; //底数变大成原来的平方
}
//如果指数为奇数
else {
power = power - 1; //把指数减去1,使其变成一个偶数
result = result * base; //此时记得要把指数为奇数时分离出来的底数的一次方收集好
power = power / 2; //此时指数为偶数,可以继续执行分半操作
base = base * base;
}
}
return result;//返回结果
}
算法优化
第一次优化
我们知道在C/C++语言中,如果赋一个小数(如1.5)的值给整型的话,整型只会记录小数点前的整数。
例如:
long long i;
i = 3 / 2;
printf("%ll",&i);//输出的结果为1
那么我们就可以根据这个来简化一下while循环里的语句。
long long fastPower(long long base, long long power) {
long long result = 1;
while (power > 0) {
//如果power是奇数,把指数为奇数时分离出来的底数的一次方收集好
if (power % 2 == 1) {
result = result * base;
}
//power = power / 2;这句语句在遇到power为奇数时,相当于之前power - 1再除于2赋的值;
//在遇到power是偶数时,就相当于这句语句
power = power / 2;
base = base * base;//把base^2计算出来
}
return result;
}
第二次优化
C语言中有“位运算”,它是比“算术运算”更底层的操作,所以如果我们使用“位运算”代替“算术运算”就能在更少时间内得到结果。
“位运算”都是二进制操作。
说明:
&为与运算符,1&1 = 1、1&0 = 0、0&1 = 0.
把一个数化为二进制数表示,那么二进制的最后一位(最右边那位)如果是1,那么这个数为奇数;如果为0,那就为偶数。比如说5的二进制表示为,10的二进制表示为。那么如果我们把一个数与1进行与运算&就能得到那个数的最右边那位数,由此就可以判断它是奇数还是偶数了。
10:(1010) & 1:(0001) 1010 & 0001 0000 —— 即0 ------------------------------------------------------------------------------------------- 5:(101) & 1:(001) 101 & 001 001 —— 即1
>>为右移运算,右移一位相当于除于2,右移两位相当于除于
所以再次优化的代码为:
long long fastPower(long long base, long long power){
long long result = 1;
while(power){ //当power等于0时停止循环
if(power&1) //如果power的当前末位为1
result = result * base; //result乘上当前的base
base = base * base; //自乘
power = power >> 1; //power往右移一位,相当于power = power / 2
}
return result;
}