一般來說,遞迴有兩種。
一種是行為的遞迴,比如樹的遍歷;另一種是計算的遞迴,比如斐波那契數列和複利計算。
我們今天嘗試對計算的遞迴進行優化。
我們從斐波那契數列作為例子
一般的**如下:
//函式
int fun(int n)
//主體
int main()
分析:上面這種解決方法有乙個致命缺陷,遞迴函式的呼叫非常消耗堆疊資源。
我們先來看一下上面程式執行時的堆疊呼叫情況:
大家可以發現,在峰值時程式開闢了10個fun函式的呼叫堆疊。
按照這種情況,當n足夠大時,那對記憶體的消耗會非常巨大。
使用遞迴的程式設計方法(特別是一些計算數值問題,比如斐波那契數列、複利)都存在這樣的通病。
原因在於擺在我們面前的遞推關係是乙個第n項與前幾項之間的關係。
解決方法:
如果我們能將這種第n項和前幾項相關的關係轉換成只和n相關的公式,那麼就解決遞迴帶來的堆疊消耗。
這種轉換的方法就是今天要介紹的常係數k階線性齊次遞推關係的顯性公式求解。
常係數k階線性齊次遞推關係是什麼?
它是一種第n項與前幾項之間的關係,形如:a[n]=c[1]*a[n-1]+c[2]*a[n-2]+…+c[k]*a[n-k]。
我們所熟知的斐波那契數列、複利等計算公式都屬於常係數k階線性齊次遞推關係。
求解常係數k階線性齊次遞推關係的顯性公式的步驟
求解的第一步:構建特徵方程
假設遞推關係如下:
則我們構建的特徵方程如下:
將特徵方程進行簡化(等式兩邊都除以r^(n-k)):
求解的第二步:求解特徵根
特徵根就是特徵方程的解。
我們這裡不介紹如何求解特徵方程,這牽涉到別的數學知識。
只是假設最終會解出t個不相等的根r[1]-r[t],其重複數量分別為m[1],m[2],…,m[t]。
求解的第四步:算出a1.0、a1.1、…、at.m的值
所有的遞推關係都會需要初始項。
我們在這一步要做的事利用將初始項代入線性方程的模板,組成線性方程組,計算出a1.0、a1.1、…、at.m的值。
這樣就最終確定了顯性方程。
以斐波那契數列為例進行實戰
使用顯性公式的**
//函式
int fun(int n)
//主體
int main()
遞推公式 黑科技
有乙個遞推式的模板,你給的值越多 main中的x值越多 遞推式得出的結果越準確 據說是杜教的模板。可不是很會用,找了幾個遞推的題,嘗試了一下,發現對於最後取模固定的題,還是蠻好用。如果每次取模都不一樣,我找的題,都用不好。好多地方看不懂 也不知道真 求不了,還是我不會用 tat 哪位dalao 可以...
約瑟夫環 遞推公式
遞推公式 f n,m f n 1,m m n f n,m f n 1,m m nf n 1,m 1 2 3 4 5 6 7 8 9 1001 2345 6789 1234 5678 91045 6789 10127 89101 24510 1245 7845 78101 81014 5458 101...
拯救LongMM (遞推公式求解)
拯救l o n g m m l a n p a s c c p p 題目描述 longdd 將軍為了平息延續數年戰亂,決定釋放戰俘營中所有的俘虜。然而,longdd 將軍不打算釋放敵軍的統帥longmm 因為這個傢伙異常聰明,是個難纏的 對手。所以longdd 將軍決定把longmm 用鍊子固定到牆...