LCS的兩種解法比較

動態規劃問題一般具有兩個要素:最優子結構與子問題重疊。

通常在求解LCS問題時,我們都會用到兩種方法:

1. momo-ization(備忘錄方法)

利用了該問題的重疊子問題特性,而重疊子問題可以使用遞歸直接解決

  0 A B C B D A B
0 0 0 0 0 0 0 0 0
B 0 0 1 1 1 1 1 1
D 0 0 1 1 1 2 2 2
C 0 0 1 2 2 2 2 2
A 0 1 1 2 2 2 3 2
B 0 1 2 2 3 3 3 4
A 0 1 2 2 3 3 4 4

所謂自上而下就是從下表最大處開始遞歸求解,最終結果爲LCS(x,y,x.length,y.length);

也就是上表中從最後一格向上回溯直到哨兵的過程,在求解每個子問題之前,我們先檢測一下這個子問題之前有沒有算過,若果有,那麼不用計算直接返回結果,如果沒有,那麼就計算這個子問題,之後將結果保存起來,方便下次再遇到時使用。。

時間複雜度T(n) = O(mn);

空間複雜度S = O(mn);//二維數組

public class TTBlcs {
	static int[][] c = new int[100][100];
	static int NIF = 9999;
	public static void main(String[] args) {		
		char[] x = {'A','B','C','B','D','A','B'};
		char[] y = {'B','D','C','A','B','A'};
		
		//TTBlcs t = new TTBlcs();
		for(int i = 0;i <= x.length;i++){//周圍有一圈哨兵均爲0
			for(int j = 0;j <= y.length;j++)
			{
				c[i][j] = NIF;
			}
		}
		System.out.print(LCS(x,y,x.length,y.length));//自上而下
	}
	
	public static int LCS(char[] x,char[] y,int i,int j){
		if(c[i][j] < NIF)//記錄如果算出來便直接返回(備忘)
			return c[i][j];
		if((i == 0)||(j == 0)){
			c[i][j] = 0;
		}
		else if(x[i-1] == y[j-1])
				c[i][j] = LCS(x,y,i-1,j-1) + 1;
		else 
				c[i][j] = LCS(x,y,i-1,j) >= LCS(x,y,i,j-1)? LCS(x,y,i-1,j):LCS(x,y,i,j-1);
		return c[i][j];
	}

}

2. 動態規劃DP:

所謂自下而上,就是從下標(1,1)處開始求解的過程,不過省去了遞歸的過程,自下而上的構建原問題的解,首先求解最基本的情況,再從最基本的情況一部一部的向上求解,比如我要求解[2…4],那麼我首先需要知道[2…2][3…4]和[2…3][4…4]的最優解,需要知道[3…4],那麼首先需要知道[3…3][4…4]的最優解,所以,倒不如我們將原問題需要的解先構建出來,再慢慢向上一層一層的構建,最後組成原問題的解!。

時間複雜度T(n) = O(mn);

空間複雜度S = O(mn);//二維數組

public class BTTlcs {
	static int[][] c = new int[100][100];
	public static void main(String[] args) {
		char[] x = {'A','B','C','B','D','A','B'};
		char[] y = {'B','D','C','A','B','A'};
		for(int k = 0;k <= x.length;k++)
		{
			c[0][k] = 0;
		}
		for(int k = 0;k <= y.length;k++)
		{
			c[k][0] = 0;
		}
		LCS(x,y);
 	}
	
	public static void LCS(char[] x,char[] y){
		for(int i = 1;i <= x.length;i++)
		{
			for(int j = 1;j <= y.length;j++)
			{
				if(x[i-1] == y[j-1])
					c[i][j] = c[i-1][j-1] + 1;
				else 
					c[i][j] = c[i-1][j] >= c[i][j-1]?c[i-1][j]:c[i][j-1];
			}
		}
		for(int i = 0;i <= x.length;i++)
		{
			for(int j = 0;j<y.length;j++)
			{
				System.out.print(c[i][j]);
			}
			System.out.print("\n");
		}
		System.out.print(c[x.length][y.length]);
	}
}
自上而下的優點是並不需要求解每一個子問題的解,而是隻求解有需要的子問題的解,缺點就是需要遞歸調用,函數調用浪費時間。自下而上的優點是並不需要遞歸調用,每個子問題求解的速度較快,缺點每個子問題都要計算,就算這個子問題的解對原問題的解並沒有任何幫助!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章