快速冪演算法及其擴充
快速冪演算法
問題引入:求
樸素演算法:令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).
首先,將遞推式
進而得到
接下來,用矩陣加速演算法求出
對於更一般的線性遞推式,構造其加速矩陣的方式超出了本文的論述範圍,在此省略。
相關文章
- 擴充套件歐幾里得演算法公式快速推導套件演算法公式
- 快速冪
- zkw 線段樹-原理及其擴充套件套件
- 【資料結構與演算法】快速冪資料結構演算法
- 分頁查詢及其擴充應用案例
- 第六章 數學問題 -------- 6.5 歐幾里得演算法及其擴充套件演算法套件
- 學習筆記----快速冪取模演算法筆記演算法
- Python 中 Singleton 的寫法及其擴充Python
- 矩陣快速冪矩陣
- 演算法學習:矩陣快速冪/矩陣加速演算法矩陣
- 快速入門pandas擴充套件庫(上)套件
- Swift快速為類擴充套件屬性Swift套件
- 淺談擴充套件歐幾里得演算法套件演算法
- 歐幾里得演算法與擴充套件歐幾里得演算法演算法套件
- chrome擴充套件應用開發快速科普Chrome套件
- 矩陣快速冪(快忘了)矩陣
- 矩陣快速冪總結矩陣
- Quick Pow: 如何快速求冪UI
- Laravel-admin 快速開發擴充套件(一)Laravel套件
- vue 快速入門 系列 —— vue loader 擴充套件Vue套件
- linux與windows下 安裝 ImageMagick 及其 php imagick擴充套件LinuxWindowsPHP套件
- 快速冪演算法(二分思想減少連乘次數)演算法
- 神奇的字串匹配:擴充套件KMP演算法字串匹配套件KMP演算法
- MySQL 複製 - 效能與擴充套件性的基石 2:部署及其配置MySql套件
- MySQL 複製 - 效能與擴充套件性的基石:概述及其原理MySql套件
- 131 Windows 環境下安裝redis 及其PHP Redis擴充套件WindowsRedisPHP套件
- Raising Modulo (快速冪取模)AI
- 【矩陣乘法】【快速冪】遞推矩陣
- 快速冪的初步認識(Java)Java
- 矩陣快速冪加速最短路矩陣
- kotlin 擴充套件(擴充套件函式和擴充套件屬性)Kotlin套件函式
- 費馬小定理 + 費馬大定理 + 勾股數的求解 + 快速冪 + 矩陣快速冪 【模板】矩陣
- HDU3221Brute-force Algorithm(矩陣快速冪&&指數降冪)Go矩陣
- 【康擴充開】及其在求全排列第k個數中的應用
- C-如何快速生成Python的C擴充套件.mdPython套件
- Kotlin學習快速入門(7)——擴充套件的妙用Kotlin套件
- 演算法系列:求冪演算法演算法
- ACM — Prepared for New Acmer 快速冪法ACM