【君义精讲】多种方法求斐波那契数列
概念
斐波那契數(shù)列(Fibonacci sequence),又稱黃金分割數(shù)列,因數(shù)學(xué)家萊昂納多·斐波那契(Leonardo Fibonacci)以兔子繁殖為例子而引入,故又稱為“兔子數(shù)列”,指的是這樣一個數(shù)列:1、1、2、3、5、8、13、21、34、……在數(shù)學(xué)上,斐波那契數(shù)列以如下被以遞推的方法定義:F(0)=1,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)
在C++中可以有多種方法求斐波那契數(shù)列
問題描述
菲波那契數(shù)列是指這樣的數(shù)列: 數(shù)列的第一個和第二個數(shù)都為1,接下來每個數(shù)都等于前面2個數(shù)之和。
給出一個正整數(shù)k,要求菲波那契數(shù)列中第k個數(shù)是多少。
題目鏈接:
OpenJudge NOI 1.5 17:菲波那契數(shù)列
1. 迭代法
- 設(shè)置變量n2,n1,表示當(dāng)前已知的倒數(shù)第二項(xiàng),和最后一項(xiàng)
- 求新的項(xiàng)t,t = n1 + n2;
- 新的倒數(shù)第二項(xiàng)是原來的最后一項(xiàng),所以使n2 = n1;
- t將會是新的最后一項(xiàng),有n1 = t;
- i為3時求出第3項(xiàng),i為4時求出第4項(xiàng),i為k時求出第k項(xiàng)。循環(huán)i從3循環(huán)到k,即可求出第k項(xiàng)
時間內(nèi)復(fù)雜度:O(n)O(n)O(n),空間復(fù)雜度:O(1)O(1)O(1)
#include<bits/stdc++.h> using namespace std; int main() {int k, n2 = 1, n1 = 1, t;//n2,n1是當(dāng)前求出的倒數(shù)第二項(xiàng),和最后一項(xiàng) cin >> k;for(int i = 3; i <= k; ++i){t = n1 + n2;n2 = n1;n1 = t;}cout << n1;return 0; }2. 遞推法
- 遞推狀態(tài):a[i]為斐波那契數(shù)列第i項(xiàng)
- 遞推關(guān)系:斐波那契數(shù)列第i項(xiàng)為其前兩項(xiàng)之和,即a[i] = a[i-1]+a[i-2]
- 初始狀態(tài):第1項(xiàng)與第2項(xiàng)值為1
時間內(nèi)復(fù)雜度:O(n)O(n)O(n),空間復(fù)雜度:O(n)O(n)O(n)
#include<bits/stdc++.h> using namespace std; int main() {int k, a[50];//a[i]為斐波那契數(shù)列第i項(xiàng)a[1] = a[2] = 1;cin >> k;for(int i = 3; i <= k; ++i)a[i] = a[i-1] + a[i-2];cout << a[k];return 0; }3. 遞歸法(一般)
- 遞歸問題:求斐波那契數(shù)列第k項(xiàng)
- 遞歸關(guān)系:想要求第k項(xiàng),必須先求第k-1項(xiàng)和第k-2項(xiàng),而后將這兩項(xiàng)加和
- 遞歸出口:斐波那契數(shù)列第1和第2項(xiàng)為1
時間內(nèi)復(fù)雜度:O(2n)O(2^n)O(2n),空間復(fù)雜度:O(n)O(n)O(n)
#include<bits/stdc++.h> using namespace std; int fib(int k)//求斐波那契數(shù)列第k項(xiàng) {if(k == 1 || k == 2)return 1;elsereturn fib(k - 1) + fib(k - 2); } int main() {int k;cin >> k;cout << fib(k);return 0; }同一種思路,用棧將遞歸轉(zhuǎn)為非遞歸寫法
#include<bits/stdc++.h> using namespace std; int main() {stack<int> stk; int n, r = 0, m;cin >> n;stk.push(n);while(stk.empty() == false){m = stk.top();//出棧stk.pop();if(m == 2 || m == 1)//如果遇到第二項(xiàng)或第一項(xiàng),直接把值加到結(jié)果res中r += 1;else{//把后兩項(xiàng)入棧stk.push(m-1);stk.push(m-2);}}cout << r;return 0; }用以上兩段代碼提交【OpenJudge NOI 1.5 17:菲波那契數(shù)列】會超時。該算法時間復(fù)雜度過高了,輸入40時,基本要1秒后才能得到結(jié)果。
4. 記憶化遞歸法
在遞歸算法的基礎(chǔ)上增加記憶狀態(tài):a[i]表示斐波那契數(shù)列的第i項(xiàng)
在遞歸時,如果要求斐波那契數(shù)列第i項(xiàng),先看這一項(xiàng)是否已經(jīng)求出來過。如果已經(jīng)求出過,那么直接取值。在求出一項(xiàng)后,將其存入記憶狀態(tài)數(shù)組中。
時間內(nèi)復(fù)雜度:O(n)O(n)O(n),空間復(fù)雜度:O(n)O(n)O(n)
5. 尾遞歸法
當(dāng)遞歸調(diào)用是整個函數(shù)體中最后執(zhí)行的語句且它的返回值不屬于表達(dá)式的一部分時,這個遞歸調(diào)用就是尾遞歸。
尾遞歸調(diào)用結(jié)束,上一次調(diào)用也就結(jié)束了,所以沒有必要存儲上一次調(diào)用中用到的臨時變量。現(xiàn)代編譯器都會針對這一特性對尾遞歸進(jìn)行優(yōu)化,減少算法的空間復(fù)雜度。
用g++編譯時,加上-O2選項(xiàng),即可開啟尾遞歸優(yōu)化。
時間內(nèi)復(fù)雜度:O(n)O(n)O(n),空間復(fù)雜度:O(1)O(1)O(1)
6. 公式法
已知求斐波那契數(shù)列的通項(xiàng)公式Fn=(1+52)n?(1?52)n5F_n = \frac{(\frac{1+\sqrt{5}}{2})^n-(\frac{1-\sqrt{5}}{2})^n}{\sqrt{5}}Fn?=5?(21+5??)n?(21?5??)n?
輸入n,代入公式,即可求值
時間內(nèi)復(fù)雜度:O(1)O(1)O(1),空間復(fù)雜度:O(1)O(1)O(1)
總結(jié)
以上是生活随笔為你收集整理的【君义精讲】多种方法求斐波那契数列的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信息学奥赛一本通 1195:判断整除 |
- 下一篇: 信息学奥赛一本通 1232:Crossi