最長公共子串LCS問題(動態規劃及備忘錄方法)
阿新 • • 發佈:2018-12-02
動態規劃與備忘錄的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];
}
}
在合適的問題上用合適的方法才是演算法的智慧和精髓。