快速幂算法及其拓展
来源:互联网 发布:7号外设淘宝店网址 编辑:程序博客网 时间:2024/06/09 17:11
快速幂算法
问题引入:求
朴素算法:令ans初始值为1,乘n次a得到
朴素算法时间复杂度:O(n)
问题:如果n非常大,比如高达
思考:朴素算法哪里可以优化?
朴素算法的特点是,连乘过程中底数始终为
我们没有必要乘15次2,注意到
然后看一下n的二进制形式:
观察发现,当n的第i位(从低到高,i>=0)为1时,
主要思想:对于a^b,当b很大时,容易超时,如果b&1=1,结果要累乘,每次循环b要右移1位,(底数a每次要累乘)例如当b=13时(1011)
于是我们有了朴素算法改进的思路:逐位判断幂次n的二进制位是否为1,若是,给答案乘上一个
改进后的算法的伪代码描述如下:
public class MyPower { public static void main(String[] args){ int a = 3; int b = 13; int m = power(a,b); System.out.println(m); } private static int power(int a, int b) { int result = 1; while(b > 0){ if((b & 1) == 1)//b的某位上为1时才累乘 result *= a; a *= a;//数学公式所得 b >>= 1;//右移1位 } return result; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
这个算法的时间复杂度是多少呢?很显然,它取决于n的二进制形式有多少位,因此
其实快速幂算法还可以递归实现,因为:
当n为偶数时,
当n为奇数时,
边界条件:当n=1,答案为
C语言描述如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
代码中加入了防溢出处理,用快速幂算法的时候比较容易犯的一个错误就是忘了考虑溢出,因此在使用的时候要看清楚数据范围,估算一下答案上界。另外,快速幂算法不推荐用递归实现,因为非递归版本不但代码也很简洁,而且效率还更优。
拓展一:快速幂模M算法
有时候所求幂的结果可能很大,于是问题要求对结果模上一个数M。我们只需要在原来算法的基础上运用一下模运算的性质即可。所谓模运算性质是指以下两条:
算法非递归实现的伪代码描述为
int runFermatPower(int a, int b, int m){ int result = 1; while (b > 0) { if ((b & 1) == 1) result = (result * a); a = (a * a) % m; b >>= 1; } return result % m; } 解释:当b=1101(2)时,从第1位开始result累乘,a = (a*a)%m加上循环可以看成表达式(a%m)^2 % m....因为(a%m)^2 % m = a^2 % m ,所以我们可以把a^13%m看成((a^1) % m) ,((a^4) % m) ,((a^8) % m)的累乘,最后对m取模。但累乘很容易造成溢出,所以我们可以把代码改成如下形式:
int runFermatPower(int a, int b, int m){ int result = 1; while (b > 0) { if ((b & 1) == 1) result = (result * a) % m; a = (a * a) % m; b >>= 1; } return result; }//在累乘过程中 res=(res*a)%m就取模,避免溢出
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
拓展二:矩阵快速幂算法
快速幂算法解决的是整数求幂的问题,而矩阵快速幂解决的是矩阵求幂问题,两者没有本质的区别。如果用C++实现,我们只要定义一个矩阵类,然后重载一下乘法运算符,原先的快速幂算法几乎不需要改变。
矩阵快速幂常常用于线性递推式的加速。以下仅举一例。
快速求斐波那契数列第n项
对于这个问题,普通求法的复杂度是O(n),现在我们用矩阵快速幂将它优化到O(logn).
首先,将递推式
进而得到
接下来,用矩阵加速算法求出
对于更一般的线性递推式,构造其加速矩阵的方式超出了本文的论述范围,在此省略。
- 快速幂算法及其拓展
- 快速幂算法及其拓展
- kmp算法及其拓展
- 欧几里得算法及其拓展
- 欧几里得算法及其拓展
- 欧几里德算法及其拓展算法
- 荷兰国旗算法及其拓展
- LRU算法思想及其拓展
- 十大基础实用算法及其拓展
- 理论: 数论(2):拓展欧几里得算法及其证明
- 三种基础排序算法及其拓展应用
- 快速排序及其变种算法
- 快速排序算法及其优化
- 快速排序算法及其注意事项
- 快速排序算法及其优化
- 快速模取幂算法及其证明
- 快速排序算法(Partition函数)分析与拓展
- BZOJ 1965 快速幂 + 拓展欧几里得
- 【Java集合】Java8 HashMap工作原理与实现
- Map集合实现的纯java购物车
- web用例设计及测试基本原则
- 如何让字典保持有序
- 考研英语笔记——时文长难句三
- 快速幂算法及其拓展
- 【正则表达式】str.replace(reg, callback) 使用
- Mysql命令行操作
- 【Mysql】select,数据简单查询整理总结
- AJAX学习(一)ajax发送请求
- String类
- 实现密码眼功
- 连续子数组求和
- 2017山东省赛C题(SDUT3895逆元法求组合数)