快速幂算法及其拓展
来源:互联网 发布:人工智能具体应用实例 编辑:程序博客网 时间:2024/06/07 09:07
摘要
本文讲解了快速幂算法的定义、复杂度证明及两种实现(递归与非递归),以及它的两个重要拓展:快速幂模M算法和矩阵快速幂。其中矩阵快速幂算法是矩阵求幂问题对整数求幂问题的借鉴,实际应用中对于线性递推式求解能起到强大的效率优化。
快速幂算法
问题引入:求
朴素算法:令ans初始值为1,乘n次a得到
朴素算法时间复杂度:O(n)
问题:如果n非常大,比如高达
思考:朴素算法哪里可以优化?
朴素算法的特点是,连乘过程中底数始终为
我们没有必要乘15次2,注意到
然后看一下n的二进制形式:
发现什么规律?
观察发现,当n的第i位(从低到高,i>=0)为1时,
于是我们有了朴素算法改进的思路:逐位判断幂次n的二进制位是否为1,若是,给答案乘上一个
改进后的算法的伪代码描述如下:
a, n, ans;ans=1;while n>0 a = a*a; if n%2 ans = ans*a; n = n/2;
这个算法的时间复杂度是多少呢?很显然,它取决于n的二进制形式有多少位,因此
其实快速幂算法还可以递归实现,因为:
当n为偶数时,
当n为奇数时,
边界条件:当n=1,答案为
C语言描述如下:
int quick_power(int a, int n){ if(n == 1) return a; int x = quick_power(a, n/2); long long ans = (long long)x*x; if(n%2) ans *= a; return (int)ans;}
代码中加入了防溢出处理,用快速幂算法的时候比较容易犯的一个错误就是忘了考虑溢出,因此在使用的时候要看清楚数据范围,估算一下答案上界。另外,快速幂算法不推荐用递归实现,因为非递归版本不但代码也很简洁,而且效率还更优。
拓展一:快速幂模M算法
有时候所求幂的结果可能很大,于是问题要求对结果模上一个数M。我们只需要在原来算法的基础上运用一下模运算的性质即可。所谓模运算性质是指以下两条:
算法非递归实现的伪代码描述为
a, n, ans, M;ans=1;while n>0 a = a*a % M; if n%2 ans = ans*a % M; n = n/2;
拓展二:矩阵快速幂算法
快速幂算法解决的是整数求幂的问题,而矩阵快速幂解决的是矩阵求幂问题,两者没有本质的区别。如果用C++实现,我们只要定义一个矩阵类,然后重载一下乘法运算符,原先的快速幂算法几乎不需要改变。
矩阵快速幂常常用于线性递推式的加速。以下仅举一例。
快速求斐波那契数列第n项
对于这个问题,普通求法的复杂度是O(n),现在我们用矩阵快速幂将它优化到O(logn).
首先,将递推式
进而得到
接下来,用矩阵加速算法求出
对于更一般的线性递推式,构造其加速矩阵的方式超出了本文的论述范围,在此省略。
- 快速幂算法及其拓展
- 快速幂算法及其拓展
- kmp算法及其拓展
- 欧几里得算法及其拓展
- 欧几里得算法及其拓展
- 欧几里德算法及其拓展算法
- 荷兰国旗算法及其拓展
- LRU算法思想及其拓展
- 十大基础实用算法及其拓展
- 理论: 数论(2):拓展欧几里得算法及其证明
- 三种基础排序算法及其拓展应用
- 快速排序及其变种算法
- 快速排序算法及其优化
- 快速排序算法及其注意事项
- 快速排序算法及其优化
- 快速模取幂算法及其证明
- 快速排序算法(Partition函数)分析与拓展
- BZOJ 1965 快速幂 + 拓展欧几里得
- JS作用域、链学习笔记
- Convert Sorted List to Binary Search Tree
- bootstrap搜索图标的使用
- 《JavaScript语言精粹》学习笔记
- POJ2001Trie树的运用
- 快速幂算法及其拓展
- bootstrap表单的其他组件
- Android客户端与PHP服务端交互(一)---框架概述
- 单词翻转(i am a student)--->>(student a am i)
- 简单的C/S 程序 windows 版
- bootstrap表单
- 程序效率相关小技巧(除去很多共知的)
- UIWindow & UIWindowLevel
- Bootstrap 表格