劍指offer 費波納數列

2021-10-02 17:47:18 字數 2970 閱讀 6852

費波納數列:

n=0, f(0)=0;

n=1,f(1)=1;

n>1, f(n)=f(n-1)+f(n-2)

這裡面一定要注意的是n >= 0, 所以需要判斷若n < 0 ,則直接return none.

處理辦法:

第一種很自然的想到遞迴:

def fibonacci(n):

#其實沒必要關心n<0,因為此處測試例項這裡沒有n<0的測試例子

if n == 0:

return 0

elif n == 1:

return 1

else:

return fibonacci(n-1)+fibonacci(n-2)

通過遞迴的基本知識我們知道其時間複雜度是2的n次方,由於函式內部2次呼叫遞迴,故每次二分,所以時間複雜度是2的n次方,所以這是非常不能接受的。舉例:當n等於100的時候,執行次數是1024的10次方,這是乙個天文資料,所以不合適,一般的直接遞迴的方法處理資料往往不是太可行。

第二種:直接遞迴的基礎上加上functools裡面的lru_catch這個裝飾器

熟悉lru_catch原理的都知道,它的底層實現是字典,字典的底層實現是hashmap,所以字典查詢的時間複雜度是1,在該數列中,我們可以發現後面的呼叫相比前面有較大的資料重複,所以如果採用此裝飾器將前面的資料儲存起來,每次相同的資料那麼只執行一次,所以時間複雜度就是n,直接大大下降。

這部分如果自己實現,那麼可以每次儲存,遞迴前檢查這個字典,這是自己實現的原理。

不自己實現就是用人家自己實現好的裝飾器,**如下:

from functools import lru_cache

@lru_cache()

def fibonacci(n):

if n == 0:

return 0

elif n == 1:

return 1

else:

return fibonacci(n-1)+fibonacci(n-2)

第三種就是最直接的用迴圈代替遞迴

def fibonacci(n):

fi = [0 ,1]

if n == 0:

return 0

elif n == 1:

return 1

else:

for i in range(2, n):

return fi[-1]

這就是該題目的解法,時間複雜度未o(n)。

下面詳細**對於遞迴的理解、自己直觀的寫遞迴函式、以及遞迴函式的一般優化手段

遞迴的理解

自己如何寫遞迴函式

遞迴的優化

如何確定乙個問題不是使用遞迴演算法

一般而言,這個問題如果能被分解 為乙個遞推式和邊界判斷,那麼此時該問題就能用遞迴來表達,但是如何才能確定該問題能寫為乙個遞推式呢?一般而言,能用遞迴的都是問題 該問題分解形狀都是類似於  幾叉數,後面的解依賴於前面的解,所以一般問題如果有此形式的話,那麼可以考慮使用遞迴演算法。

先將問題逆向考慮,因為要寫遞推式從n開始發現n-1、n-2、n-等等的關係,所以要逆向考慮,看執行該行文正向和逆向過程是否一樣。

比如青蛙跳台,正著跳和逆著跳結果是一致的,所以滿足此步。

確定該問題是否適合用遞迴                         問題可能幾叉分解、依賴於前面的結果,考慮使用遞迴即其迴圈優化、裝飾器優化

使用遞迴演算法的第一步就是寫出                 邊界條件和遞迴表示式,這一點要切記。

當寫出遞推式以後                                       進行遞推式化解,盡可能簡單

此時可以直接遞迴,也可以迴圈處理了,遞迴表示式本身就是一種迴圈,依賴於前面的結果麼,所以迴圈往後面計算處理即可。

基於遞迴的斐波那契數列的兩個題目

青蛙跳台階:分析。青蛙跳台階按照上述步驟處理,本質上就是乙個費波納且數列。

class solution:

def jumpfloor(self, n):

fi = [1, 2]

if n >= 0 and n <= 2:

return n

elif n < 0 :

return none

else:

for i in range(2, n):

return fi[-1]

青蛙**跳台階: 當然寫出遞推式,發現就是f(n)=f(n-1)+f(n-1)+f(n-2)+...f(2)+f(1)+1,所以迴圈最後一項就是前面所有項的和,這樣的問題肯定不能用遞迴處理了,那麼智慧型迴圈處理了。

class solution:

def jumpfloorii(self, number):

# write code here

taijie = [0, 1]

if number < 0:

return none

elif number >=0 and number <=1:

return taijie[number]

else:

for i in range(2, number+1):

return taijie[-1]

但是可以發現,f(n-1)=f(n-2)+...f(2)+f(1)+1,所以上述的f(n)=2f(n-1),直接簡化了迴圈條件,所以這是對於遞迴問題的簡化以及遞迴條件的變形,人人呢屬於上述範疇。

《劍指Offer》斐波納契數列

描述 查詢斐波納契數列中第 n 個數。所謂的斐波納契數列是指 斐波納契數列的前10個數字是 0,1,1,2,3,5,8,13,21,34 樣例 給定 1,返回 0 給定 2,返回 1 給定 10,返回 34 解答解析 這道題可以使用遞迴來解答,但是遞迴所消耗的時間複雜度與空間複雜度都比較大,因此我們...

PHP實現費波納奇數列

迴圈制 初始化前兩個引數為1,其中定義陣列來做的原因是方便理解 迴圈開始,以下標為2開始處理 不斷往陣列中新增,當前迴圈次數的下表對應的值是前兩個值得和 array array array 0 1 array 1 1 for i 2 i 10 i print r array 遞迴處理 定義結束遞迴的...

劍指offer 斐波那契數列

題目1描述 寫乙個函式,輸入n,求斐波那契數列的第n項。斐波那契數列的定義如下 f n 0 n 0 f n 1 n 1 f n f n 1 f n 2 n 1 分析描述 在大多數的c語言教科書中,一般會用遞迴求斐波那契數列。如下 long long fibonacci unsigned int n ...