最长公共子串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];
	}

}

在合适的问题上用合适的方法才是算法的智慧和精髓。

猜你喜欢

转载自blog.csdn.net/u013453787/article/details/83009854