1. 程式人生 > >fibonacci數列的兩種求解方式:基礎遞迴VS動態規劃

fibonacci數列的兩種求解方式:基礎遞迴VS動態規劃

動態規劃的核心是要找到“狀態”和“狀態轉移方程”,“狀態"用來描述該問題的子問題的解。

/*
 * 基礎解法,按照遞迴方法求解,該演算法的運算時間是指數級增長的
 * 這種演算法對於相似的子問題進行了重複的計算,因此不是一種高效的演算法
 */
public class FibonacciRecursion {
	
	//-----------計算Fibonacci數列值的遞迴函式--------------
	public static int fib(int n){
		if(n==1||n==2){//序列中第1,2個數為1
			return 1;
		}
		return fib(n-1)+fib(n-2);
	}
	
	public static void main(String[] args) {
		int i=46;
		long begin=System.currentTimeMillis();
		System.out.println("fib("+i+"):"+fib(i));
		long cost=System.currentTimeMillis()-begin;
		System.out.println("耗時:"+cost+"ms");
	}
}

當n=5時,fib(5)的計算過程如下:

  1. fib(5)
  2. fib(4) + fib(3)
  3. (fib(3) + fib(2)) + (fib(2) + fib(1))
  4. ((fib(2) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))
  5. (((fib(1) + fib(0)) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))

由上面可以看出,這種演算法對於相似的子問題進行了重複的計算,因此不是一種高效的演算法。

下面採用動態規劃的思想來求解

/*
 * 可以通過儲存已經算出的子問題的解來避免重複計算
 * 即使用動態規劃的技術
 */
public class FibonacciDP {

	// ----------使用動態規劃(DP)求fibonacci數列的值------------
	public static int fib(int n) {
		int[] array = new int[n];//用來儲存動態規劃過程中的狀態
		array[0] = 1;
		array[1] = 1;
		for (int i = 2; i < n; i++)
			array[i] = array[i - 1] + array[i - 2];//動態規劃的狀態轉移式
		return array[n-1];
	}

	public static void main(String[] args) {
		long begin=System.currentTimeMillis();
		System.out.println("fib(46):"+fib(46));
		long cost=System.currentTimeMillis()-begin;
		System.out.println("耗時:"+cost+"ms");
	}
}

/*
 * 採用動態規劃求解最長非降子序列的長度
 */
public class Lis {
	public static void main(String[] args) {
		int[] src = { 1, 2, 5, 3, 4, 9, 10, 6, 7, 8 };
		System.out.println("本例的最長非降子序列:1 2 3 4 6 7 8");
		System.out.println("<span style="line-height: 22.3999996185303px; font-family: sans-serif;">最長非降子序列長度</span>:" + lis(src));
	}

	public static int lis(int[] src) {
		int n = src.length;
		int[] dis = new int[n];// 儲存"狀態"的陣列
		int len = 1;// 返回最大非降子序列的長度
		for (int i = 0; i < n; i++) {
			dis[i] = 1;
			for (int j = 0; j < i; j++) {
				if (src[j] < src[i] && dis[j] + 1 > dis[i])
					dis[i] = dis[j] + 1;
			}
			if (dis[i] > len) {
				len = dis[i];
			}
		}
		return len;
	}
}
參考文獻(關於動態規劃)
http://www.hawstein.com/posts/dp-novice-to-advanced.html
http://blog.csdn.net/woshioosm/article/details/7438834