1. 程式人生 > >牛客網線上程式設計專題《劍指offer》(8)跳臺階

牛客網線上程式設計專題《劍指offer》(8)跳臺階

題目連線:

題目:

解題思路:

1. 問題分析

設f(n)表示青蛙跳上n級臺階的跳法數。 當只有一個臺階時,即n = 1時,只有1中跳法; 當n = 2時,有2種跳法; 當n = 3 時,有3種跳法; 當n很大時,青蛙在最後一步跳到第n級臺階時,有兩種情況: 一種是青蛙在第n-1個臺階跳一個臺階,那麼青蛙完成前面n-1個臺階,就有f(n-1)種跳法,這是一個子問題。 另一種是青蛙在第n-2個臺階跳兩個臺階到第n個臺階,那麼青蛙完成前面n-2個臺階,就有f(n-2)種情況,這又是另外一個子問題。

兩個子問題構成了最終問題的解,所以當n>=3時,青蛙就有f(n)=f(n-1)+f(n-2)種跳法。 上面的分析過程,其實我們用到了動態規劃的方法,找到了狀態轉移方程,用數學方程表達如下:

仔細一看,這不就是傳說中的著名的斐波那契數列,但是與斐波那契數列的還是有一點區別,斐波那契數列從0開始,f(0)=0,f(1)=1,f(2)=1。斐波那契數列(Fibonacci Sequence),又稱黃金分割數列,因為當n趨於無窮大時,前一個數與後一個數的比值無限接近於黃金比例。

2.解題方法

(1)遞迴實現

有了初始狀態和狀態轉移方程,那麼程式設計實現求解就不難了,遞迴演算法實現如下:

package kuaishou;

public class qingwataijie {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(JumpFloor(5));
	}
	
	private static int JumpFloor(int target) {
		if(target == 1) {
			return 1;
		}else if(target == 2) {
			return 2;
		}else {
			return JumpFloor(target-1)+JumpFloor(target-2);
		}
	}

}

 但是我們都知道遞迴的時間複雜度和空間複雜度都很大,因此該遞迴演算法的時間複雜度為O(2^{n}),空間複雜度為O(n)。

不明白時間複雜度和空間複雜度怎麼算的,可以看一下這篇文章。

(2)迭代實現

能用遞迴實現的演算法,當然我們也能用迭代方法實現。

遞迴演算法的一個缺點就是重複計算。我們可以把已經得到的數列中間項儲存起來,如果下次需要計算的時候,我們先查詢一下,如果前面已經計算過就不用再重複計算了。

迭代法:首先根據f(0)和f(1)計算出f(2),在根據f(1)和f(2)計算出f(3)......依次類推就可以算出第n項了。

package kuaishou;

public class qingwataijie {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(JumpFloor(5));
	}
	
	private static int JumpFloor(int target) {
		if(target == 1) {
			return 1;
		}else if (target == 2) {
			return 2;
		}else {
			int res = 0; 
			int a = 1;
			int b = 2;
			for(int i=3; i<=target; i++) {
				res = a + b;
				a = b;
				b = res;
			}
			return res;
		}
	}

}

 迭代法實現的時間複雜度為O(n),空間複雜度為O(1)。

這個演算法是時間複雜度最低的演算法嗎?當然不是,最快的應該是下面的矩陣法。

(3)矩陣法

根據上面的地推公式,我們可以得到:

有了這個公式,我們只需要求得矩陣,即可得到f(n)。現在的問題轉為如何求矩陣的乘方。如果只是簡單地從0開始迴圈,n次方需要n次運算,那其時間複雜度仍然是O(n),並不比前面的方法快。但是我們可以考慮乘方的如下性質:

$$ a^{n}=\left\{ \begin{aligned} a^{\frac{n}{2}}.a^{\frac{n}{2}} ,& \mbox{if }n \mbox{ is even} \\ a^{\frac{\left ( n-1\right )}{2}}.a^{\frac{\left ( n-1\right )}{2}}.a , & \mbox{if }n \mbox{ is odd}\\ \end{aligned} \right. $$

從上面的公式中我們可以看出,想求得n次方,就要先求n/2次方,再把n/2次方的結果平方一下即可。這可以用遞迴的思想實現。