import java.util.Arrays;/// LCS问题/// 动态规划/// 时间复杂度: O(len(s1)*len(s2))/// 空间复杂度: O(len(s1)*len(s2))publicclassLCS1{privateint[][] memo;public String lcs(String s1, String s2){if(s1 == null || s2 == null)thrownewIllegalArgumentException("s1 and s2 can not be null.");if(s1.length()==0|| s2.length()==0)return"";
memo =newint[s1.length()][s2.length()];for(int i =0; i < s1.length(); i ++)
Arrays.fill(memo[i],-1);lcs(s1, s2, s1.length()-1, s2.length()-1);returngetLCS(s1, s2);}// 求s1[0...m]和s2[0...n]的最长公共子序列的长度值privateintlcs(String s1, String s2,int m,int n){if(m <0|| n <0)return0;if(memo[m][n]!=-1)return memo[m][n];int res =0;if(s1.charAt(m)== s2.charAt(n))
res =1+lcs(s1, s2, m -1, n -1);else
res = Math.max(lcs(s1, s2, m -1, n),lcs(s1, s2, m, n -1));
memo[m][n]= res;return res;}// 通过memo反向求解s1和s2的最长公共子序列private String getLCS(String s1, String s2){int m = s1.length()-1;int n = s2.length()-1;
StringBuilder res =newStringBuilder("");while(m >=0&& n >=0)if(s1.charAt(m)== s2.charAt(n)){
res = res.insert(0, s1.charAt(m));
m --;
n --;}elseif(m ==0)
n --;elseif(n ==0)
m --;else{if(memo[m-1][n]> memo[m][n-1])
m --;else
n --;}return res.toString();}publicstaticvoidmain(String[] args){
String s1 ="ABCDGH";
String s2 ="AEDFHR";
System.out.println((newLCS1()).lcs(s1, s2));
s1 ="AAACCGTGAGTTATTCGTTCTAGAA";
s2 ="CACCCCTAAGGTACCTTTGGTTC";
System.out.println((newLCS1()).lcs(s1, s2));}}
/// LCS问题/// 动态规划/// 时间复杂度: O(len(s1)*len(s2))/// 空间复杂度: O(len(s1)*len(s2))publicclassLCS2{public String lcs(String s1, String s2){int m = s1.length();int n = s2.length();// 对memo的第0行和第0列进行初始化int[][] memo =newint[m][n];for(int j =0; j < n ; j ++)if(s1.charAt(0)== s2.charAt(j)){for(int k = j ; k < n ; k ++)
memo[0][k]=1;break;}for(int i =0; i < m ; i ++)if(s1.charAt(i)== s2.charAt(0)){for(int k = i ; k < m ; k ++)
memo[k][0]=1;break;}// 动态规划的过程for(int i =1; i < m ; i ++)for(int j =1; j < n ; j ++)if(s1.charAt(i)== s2.charAt(j))
memo[i][j]=1+ memo[i-1][j-1];else
memo[i][j]= Math.max(memo[i-1][j], memo[i][j-1]);// 通过memo反向求解s1和s2的最长公共子序列
m = s1.length()-1;
n = s2.length()-1;
StringBuilder res =newStringBuilder("");while(m >=0&& n >=0)if(s1.charAt(m)== s2.charAt(n)){
res.insert(0, s1.charAt(m));
m --;
n --;}elseif(m ==0)
n --;elseif(n ==0)
m --;else{if(memo[m-1][n]> memo[m][n-1])
m --;else
n --;}return res.toString();}publicstaticvoidmain(String[] args){
String s1 ="ABCDGH";
String s2 ="AEDFHR";
System.out.println((newLCS2()).lcs(s1, s2));
s1 ="AAACCGTGAGTTATTCGTTCTAGAA";
s2 ="CACCCCTAAGGTACCTTTGGTTC";
System.out.println((newLCS2()).lcs(s1, s2));}}
/// LCS问题/// 动态规划, 躲避边界条件/// 时间复杂度: O(len(s1)*len(s2))/// 空间复杂度: O(len(s1)*len(s2))publicclassLCS3{public String lcs(String s1, String s2){int m = s1.length();int n = s2.length();// memo 是 (m + 1) * (n + 1) 的动态规划表格// memo[i][j] 表示s1的前i个字符和s2前j个字符的最长公共子序列的长度// 其中memo[0][j] 表示s1取空字符串时, 和s2的前j个字符作比较// memo[i][0] 表示s2取空字符串时, 和s1的前i个字符作比较// 所以, memo[0][j] 和 memo[i][0] 均取0// 我们不需要对memo进行单独的边界条件处理 :-)int[][] memo =newint[m +1][n +1];// 动态规划的过程// 注意, 由于动态规划状态的转变, 下面的i和j可以取到m和nfor(int i =1; i <= m ; i ++)for(int j =1; j <= n ; j ++)if(s1.charAt(i -1)== s2.charAt(j -1))
memo[i][j]=1+ memo[i -1][j -1];else
memo[i][j]= Math.max(memo[i -1][j], memo[i][j -1]);// 通过memo反向求解s1和s2的最长公共子序列
m = s1.length();
n = s2.length();
StringBuilder res =newStringBuilder("");while(m >0&& n >0)if(s1.charAt(m -1)== s2.charAt(n -1)){
res.insert(0, s1.charAt(m -1));
m --;
n --;}elseif(memo[m -1][n]> memo[m][n -1])
m --;else
n --;return res.toString();}publicstaticvoidmain(String[] args){
String s1 ="ABCDGH";
String s2 ="AEDFHR";
System.out.println((newLCS3()).lcs(s1, s2));
s1 ="AAACCGTGAGTTATTCGTTCTAGAA";
s2 ="CACCCCTAAGGTACCTTTGGTTC";
System.out.println((newLCS3()).lcs(s1, s2));}}