首先來講一下遞歸,咱們不講概念,我只說一下遞歸自己,有須要的同窗請自行查閱資料。java
遞歸分兩個階段,遞和歸算法
咱們用數學表達式來看一下什麼是遞歸的表示(x的y次冪)函數
f(x,y) = x * f(x, y - 1)
f(x, 1) = x3d
上面的結構就是遞歸的數學表示啦,第一個函數式是定義了函數如何遞下去,第二個函數式定義了函數如何歸回來。code
上面的例子實際上是求x的y次冪,按照遞歸的思想,咱們計算表達式的結果須要把x連乘y次,乍看起來沒什麼,但若是當y的次數足夠大的時候,程序就可能會執行很慢,更甚至會發生爆棧的狀況(也就是一般說的棧溢出)。blog
好比咱們求2的21次冪的話,常規算法就是把2連乘21次,相應代碼以下:遞歸
/** * @param x 底數 * @param y 指數 * @return x的y次冪 */ long power(int x, int y) { long res = 1; for(int i = 1; i <= b; i++) { res *= a; } return res; }
是否是以爲有點low,那咱們用遞歸的思想寫一個方法數學
/** * @param x 底數 * @param y 指數 * @return x的y次冪 */ long power(int x, int y) { if(y == 1) { return x; } else { return x * power(x, y-1) } }
上面兩個方法都很差,由於複雜度仍是O(n)class
因此爲了解決這個問題,咱們引出一個概念:整數快速冪循環
所謂快速冪,就是快速求冪次。
利用咱們學過二進制,好比 21 ,它的二進制數字爲 10101 ,也就是他能夠分紅21 = 16 + 0 + 4 + 0 + 1,也就是21 = 1 * 2^4 + 1 * 2^2 + 1 * 2^0。
那麼咱們計算2的21次冪就能夠這麼算了 咱們這樣分解2^21 = 2^16 * 2^4 * 2^1
若是要下降複雜度,首先應該是下降循環次數,再次就是下降重複計算的次數
先看代碼
/** * @param x 底數 * @param y 指數 * @return x的y次冪 */ long power(int x, int y) { long res = 1; while(y) { if(y&1) { res = res * x; //若是二進制最低位爲1,則乘上x^(2^i) } x = x * x; //將x平方 y >>= 1; //右移 至關於n/2 } return res; }
這裏解釋一下,y&1是進行的與運算,至關於判斷y的二進制表示最低爲是否是1,>>這個是右移運算符,就是把當前數的二進制表示向右移動一位,就是把10101變成1010.1,浮點後面的數字會自動丟棄,也就是10101右移一位變成了1010
如今咱們模擬一下程序是如何跑的 power(2, 21)
以上就是線性遞歸了,那什麼是線性遞歸?
線性遞歸的意思就是 遞歸的次數 和 遞歸參數 知足線性表達式關係
也就是遞歸函數f(x) 須要遞歸的次數爲 a*x+b 其中ab爲常數
所謂發散遞歸呢就是遞歸函數f(x)的遞歸次數是非線性的,例如x³-5x²-2x-8,這個函數式就是非線性的。 咱們知道,當x的次數大於1的時候,在平面直角座標系中會發生指數爆炸的狀況。
根據上面咱們說到的知識,也就意味着,發散遞歸會比線性遞歸更早的達到爆棧的臨界點。
解決這一問題,就須要矩陣快速冪了。
要明白本文以後的內容,請你們回憶複習一下行列式和矩陣的基本概念和運算知識。
x > 2: f(x) = f(x-1) + f(x-2)
x = 2: f(x) = 1
x = 1: f(x) = 1
一樣的咱們先用遞歸的算法來表示,以下:
int fei(int n) { if(n == 1||n == 2) { return 1; } return fei(n-1) + fei(n-2); }
很簡潔的代碼,不在解釋啦
至於這個遞歸執行了多少次,太具體的我也沒算反正差很少是2的n次方吧
最簡單算法就是,看結果是多少,就遞歸了多少次。
由於歸回來的結果老是1,也就是好多個1相加,最後返回的計算結果。
已知:
矩陣化表達以下
推導式
推導過程我就不寫了,基本的矩陣運算。而後咱們可得出下面的推導過程
那麼當a=n-1的時候,被乘矩陣爲
看看 咱們得出了什麼,由一個發散遞歸變成了一個線性遞歸(斐波那契變成冪運算)
成功降維,咱們只須要再把這個冪運算的遞歸形式變成整數快速冪就能夠了
參照上面的證書快速冪,因此咱們只須要把底數的參數由原來的整數換成矩陣就能夠了。
以上呢,就是快速冪了,不管是整數快速冪仍是指數快速冪,都是爲了簡化運算減小遍歷次數。使得算法複雜度陡然降低。
若有錯誤請指正,若有想法可交流。