假設你正在爬樓梯。需要 n 步你才能到達樓頂。
每次你可以爬 1 或 2 個臺階。你有多少種不同的方法可以爬到樓頂呢?
注意:給定 n 是一個正整數。
示例 1:
輸入: 2 輸出: 2 解釋: 有兩種方法可以爬到樓頂。 1. 1 步 + 1 步 2. 2 步
示例 2:
輸入: 3 輸出: 3 解釋: 有三種方法可以爬到樓頂。 1. 1 步 + 1 步 + 1 步 2. 1 步 + 2 步 3. 2 步 + 1 步
這是一個很經典的問題了,記得高中的數學課上就講過這個問題。這個問題如果按照正常的邏輯來思考,從第一層爬到頂有多少種方式,那就太複雜了,不符合我們算法求解的要求。
既然從第一層向上推導太複雜,那我們可以換一個思路:那就是從頂層往回退。假如我們要爬n層樓梯,還剩一層就到頂了,那麼我們再向上走一步就能到頂,如果設爬上n-1層樓梯的方式有f(n-1)種,那麼在這種情況下,我們爬上第n層也有f(n-1)種方式。
但是,還沒有結束,因爲最後一步可以爬1層也可以爬2層,那麼我們爬上最後一層可以是從n-2層一次爬了2層到第n層。這種情況下,爬n層樓梯又有了f(n-2)中方式。
由於每次只能上1層或者2層樓梯,所以到達第n層的最後一步就只能是從n-1層爬1層,從n-2層爬兩層。那麼爬上n層樓梯的總方式就爲f(n)=f(n-1)+f(n-2)。有沒有很熟悉這個公式啊,對,這就是著名的斐波那契數列啊
既然是熟悉的斐波那契數列,那就不多說了吧,直接上代碼:
public int climbStairs(int n) { if (n == 0) { return 0; } if (n == 1) { return 1; } if (n == 2) { return 2; } return climbStairs(n - 1) + climbStairs(n - 2); }
這是最簡單的斐波那契數列的寫法,使用了遞歸,但是這種寫法的時間複雜度太大。
提交結果:
於是又經過思考,耗時太長的原因是使用了遞歸,能不能不用遞歸來實現呢?
public int climbStairs(int n) { if (n <= 1) { return 1; } int res = 0; int n1 = 1; int n2 = 1; for (int i = 2; i <= n; ++i) { res = n2 + n1; n1 = n2; n2 = res; } return res; }
這次改進之後好多了