快速幂算法

现在越来越深刻的理解到 算法 =  数学 这个公式了,当兴致勃勃要写一道算法题的时候,经常被数学给难住,代码还没开始编写‍♀️,一大半时间都在思考数学问题(ps:笨的人只能靠努力了~~花时间了~~)。

今天就以快速幂算法为例,让大家感受一下数学之美、算法之美。

一、幂运算

快速幂,顾名思义就是快速做运算(剩下大把的时间…………)。那什么是幂运算呢? 

 答:幂(power)是指乘方运算的结果。n^m指该式意义为m个n相乘。把n^m看作乘方的结果,叫做n的m次幂,也叫n的m次方,其中,n是底数,m是指数

举例:2^3,指的是3个2相乘。因为2^3=8,所以8是乘方的结果,此时称为2的3次幂,也叫做2的3次方。

二、幂的数学表示和规则

为了说清楚快速幂的基本原理,此处引入幂在数学中表示方式和运算规则。一般而言,如果你想表示a的b次方,在数学上可以这样写:

比如:想要表示2的3次方5的2次方,可以这样写:

快速幂算法_第1张图片 

如果做乘法运算的话,有这样一个规则:底数相同,指数相加例子如下:

且有这样以下的式子恒成立

三、快速幂的基本原理 

如果我们换一个角度看问题,我们可以将这个数进行这样的拆解:

式子1 

 如果以上式子理解起来还是有一些困难的话,我们再看看这个式子:这个式子和上面的式子是等价的,运算次数也是4次。

式子2 

四、循环求快速幂 

基本思想:参考式子1,将底数不断变大,指数缩小。

现在需要编写循环代码求解以下式子:

快速幂算法_第2张图片 如何将底数不断变大,指数不断缩小求解答案呢?

参考代码如下:快速幂算法_第3张图片

 ​​​在这里,你们可以将2^6代入到代码中进行模拟。感受一下循环求解快速幂的过程。

快速幂算法_第4张图片 快速幂算法_第5张图片

快速幂算法_第6张图片 总结:快速幂是一个将底数等价增大,指数等价缩小的过程。

当指数b是偶数时,有:

快速幂算法_第7张图片

当指数b是奇数时,有: 

快速幂算法_第8张图片

五、递归求快速幂 

基本思想:参考式子2,将大规模问题变成小规模问题‍,从而得出最终的答案。

比如:现在要求解2^6的值,那么可以将2^6看成:2^6 = 2^3 * 2^3,这个时候问题规模由2^6变成了2^3,而2^3 = 2^2 * 2^1,此时问题规模由2^3变成了2^2,然后把2^2看成2^2 = 2^1 * 2^1,此时问题规模由2^2变成了2^1,2^1的结果为2,已经知道最小问题规模的答案为2,此时一步一步反推回去,最终能够求出2^6等于64。

快速幂算法_第9张图片

参考代码如下:

快速幂算法_第10张图片

六、快速幂中的取余运算  

在做和快速幂有关的题目的时候,经常会发现有个取余运算,主要原因是因为现在oj网站的题或者竞赛的题,如果a的b次幂且b很大(b很大会爆空间),那么题中大多会让你把结果对一个数取余也就是求模,例如a^b%c这种。

【题目描述】
        假设今天是星期日,那么过a的b次方天之后是星期几☕?

【输入】
        两个正整数a,b,中间用单个空格隔开。0

【输出】
        一个字符串,代表过a的b次方天之后是星期几

        其中,Monday是星期一,Tuesday是星期二,Wednesday是星期三,Thursday是星期四,Friday是星期五,Saturday是星期六,Sunday是星期日。

【输入样例】
        3 2000

【输出样例】
        Tuesday

数学上有一个公式:(a*b)%m = (a%m * b%m) %m 

#include
using namespace std;
int a,b,m=7,res=1;
int main() {
	cin >> a >> b;
	while(b!=0) {
		if(b%2==1) {
			res = res * a % m;
		}
		a = a * a % m;
		b = b/2;
	}
	switch(res) {
		case 0: {
			cout << "Sunday" << endl;
			break;
		}
		case 1: {
			cout << "Monday" << endl;
			break;
		}
		case 2: {
			cout << "Tuesday" << endl;
			break;
		}
		case 3: {
			cout << "Wednesday" << endl;
			break;
		}
		case 4: {
			cout << "Thursday" << endl;
			break;
		}
		case 5: {
			cout << "Friday" << endl;
			break;
		}
		case 6: {
			cout << "Saturday" << endl;
			break;
		}
	}
	return 0;
}

假设今天是周日,以求解 2^3是星期几为例,即求2^3%7的结果 ,通过公式我们知道:

(2 * 2 * 2) % 7 = (2%7 * (2*2)%7) % 7。

接下来,我们对代码进行数据模拟,试试看当a=2,b=3时,能否得到以上式子。

第一步:输入a、b,a=2,b=3

第二步:判断b是否为0,b不为0,且b为奇数,得到 res = 2%7

第三步:a的值重新设为 a = (2*2)%7

第四步:b为1,执行 res = (2%7 * (2*2)%7) % 7

第五步:计算a、b,b为0,退出while循环。

通过以上五个步骤的模拟,可以知道,最终res的值和公式求解的值一致


七:总结

编写通俗易懂的算法文章是一件特别有意思、有成就感的事情,接下来我将编写各种专题算法,同时配备视频,有需要的小伙伴可以喊我一声⛳。

你可能感兴趣的:(快速幂算法,分治算法,数据结果与算法,少儿编程,蓝桥杯,ACM,计算机考研)