1. 程式人生 > >最長公共子串LCS問題(動態規劃及備忘錄方法)

最長公共子串LCS問題(動態規劃及備忘錄方法)

動態規劃與備忘錄的LCS實現

動態規劃從下到上積累能量,中間值全部記錄以方便後期計算時呼叫,但有些時候很多記錄的值用不到,這個時候備忘錄方法則更好,可以減少記錄的值,其特點是自上到下,記錄少部分值。以LCS最長公共子串問題威力,分別給出兩種實現。

  • 動態規劃法:
package longestCommonSubstring;

public class LCS_1 {

	public static void main(String[] args) {
		// TODO 自動生成的方法存根
		String s1 = "adfdsgdsgadsg";
		String s2=
"sddsgdsgafsdf"; LCS(s1, s2); } public static void LCS(String s1, String s2) { char[] a = s1.toCharArray(); char[] b = s2.toCharArray(); int a_length = a.length; int b_length = b.length; int[][] lcs = new int[a_length + 1][b_length + 1]; for(
int i = 0; i <= a_length; i++) { lcs[i][0] = 0; } for(int j = 0; j <= b_length; j++) { lcs[0][j] = 0; } for(int i = 1; i <= a_length; i++) { for(int j = 1;j <= b_length; j++) { if(a[i-1] == b[j-1]) { lcs[i][j] = lcs[
i-1][j-1] + 1; } else { lcs[i][j] = Math.max(lcs[i-1][j], lcs[i][j-1]); } } } for (int i = 0; i <= a_length; i++) { for (int j = 0; j <= b_length; j++) { System.out.print(lcs[i][j]+","); } System.out.println(); } System.out.println("s1和s2的最長公共子串長度是: " + lcs[a_length][b_length]); LCS_Print(lcs,a,b); } private static void LCS_Print(int[][] lcs, char[] a, char[] b) { int a_length = a.length; int b_length = b.length; int maxlen = lcs[a_length][b_length]; char[] comStr = new char[maxlen]; int i = a_length, j = b_length; while(maxlen > 0) { //起碼有一個字母在公共子串裡 if(lcs[i][j] != lcs[i-1][j-1]) { if(lcs[i-1][j] == lcs[i][j-1]) { comStr[maxlen-1] = a[i-1]; i--;j--; maxlen--; } else if(lcs[i-1][j] > lcs[i][j-1]) { i--; } else { j--; } } else { i--; j--; } } System.out.print("最長公共子串是: "); System.out.println(comStr); } }
  • 備忘錄方法:
package longestCommonSubstring;

public class LCS_2 {
	static int[][] lcs;
	public static void main(String[] args) {
		// TODO 自動生成的方法存根
		String s1 = "adfdsgdsgadsg";
		String s2= "sddsgdsgafsdf";
		LCS(s1, s2);
	}

	private static void LCS(String s1, String s2) {
		// TODO 自動生成的方法存根
		char[] a = s1.toCharArray();
		char[] b = s2.toCharArray();
		int a_length = a.length;
		int b_length = b.length;
		lcs = new int[a_length+1][b.length+1];
		for(int i = 0; i <= a_length ;i++) {
			for(int j = 0; j <= b_length; j++) {
				lcs[i][j] = -1;
			}
		}
		lookUpChain(a, b, a_length, b_length);
		System.out.println("最長公共子串是:" + lookUpChain(a, b, a_length, b_length));
		LCS_Print(a,b);
	}

		private static void LCS_Print(char[] a, char[] b) {
 
        int a_length = a.length;  
        int b_length = b.length;
		
		int maxlen = lcs[a_length][b_length];
		char[] comStr = new char[maxlen];
		int i = a_length, j = b_length;
		while(maxlen > 0) {
			//起碼有一個字母在公共子串裡
			if(lcs[i][j] != lcs[i-1][j-1]) {
				if(lcs[i-1][j] == lcs[i][j-1]) {
					comStr[maxlen-1] = a[i-1];
					i--;j--;
					maxlen--;
				}
				else if(lcs[i-1][j] > lcs[i][j-1]) {
					i--;
				}
				else {
					j--;
				}
			}
			else {
				i--;
				j--;
			}
		}
		System.out.print("最長公共子串是: ");
		System.out.println(comStr);
	}

	private static int lookUpChain(char[] a, char[] b,int i, int j) {
		
		if(lcs[i][j]>-1)		
			return lcs[i][j];
		
		if(i==0||j==0)		
			lcs[i][j]=0;	
		else{		
			if(a[i-1]==b[j-1])	
				lcs[i][j]=lookUpChain(a,b,i-1,j-1) + 1;
			else			
				lcs[i][j]=Math.max(lookUpChain(a,b,i,j-1),lookUpChain(a,b,i-1,j));	
			}       
		return lcs[i][j];
	}

}

在合適的問題上用合適的方法才是演算法的智慧和精髓。