15.4.4
1)使用 2*min(m,n)个条目计算LCS长度
实际上,计算特定的 C[i,j]只需用到 C[i-1,j-1] 或者 C[i-1,j] C[i,j-1]。所以交替使用两个大小为min(m,n)的数组表示 当前行 和 上一行 即可。
// Use dynamic programming to calculate LCS length of two strings with a 2*min(m,n) size table
public static <T> int findLCSLengthBy2Array(T[] longString,T[] shortString){
int size = Math.min(longString.length, shortString.length)-1;
int length = 0;
if(size>0){
int[][] lcs = new int[2][size+1];
for(int i=1;i<longString.length;i++){
int k=1;
for(int j=1;j<shortString.length;j++){
if(longString[i]==shortString[j]){
lcs[k][j] = lcs[k-1][j-1] +1;
}else if(lcs[k-1][j] >= lcs[k][j-1]){
lcs[k][j] = lcs[k-1][j];
}else{
lcs[k][j] = lcs[k][j-1];
}
}
// Assign current row to previous row.
lcs[k-1] = lcs[k].clone();
// And reset current row.
for(int m=0;m<lcs[1].length;m++){
lcs[1][m] = 0;
}
}
// Final result is saved at lcs[previous][min(m,n)]
length = lcs[0][size];
}
return length ;
}
2) 使用 min(m,n) +O(1) 的条目计算 LCS长度。
设计算到 i 行 j 列,于是 C[i,j-1]为已知,而从 j 到 min(m,n)列未被计算,可以用于表示 C[i-1,j]。于是只剩下 C[ i-1 , j-1],用额外的一个变量或定义多一个数组元素保存。在每次计算 C[i,j]前保存好 C[i-1, j-1]用于C[i,j+1]的计算。
// Use dynamic programming to calculate LCS length of two strings , with a min(m,n)+1 size array
public static int findLCSLengthBy1Array(char[] longArray,char[] shortArray){
int size = Math.min(longArray.length, shortArray.length)-1;
int length = 0;
if(size>0){
int[] lcs = new int[size+1];
for(int i=1;i<longArray.length;i++){
int lcs0 = lcs[0];
for(int j=1;j<shortArray.length;j++){
// Save lcs[j] acting as C[i-1,j-1] first for the next calculation.
int swap = lcs[j];
if(longArray[i]==shortArray[j]){
// If two chars match, calculate lcs[j] = current C[i-1,j-1] + 1
lcs[j] = lcs[0]+1;
}else if(lcs[j] >=lcs[j-1]){
lcs[j] = lcs[j];
}else{
lcs[j] = lcs[j-1];
}
// Get C[i,j] after it is modified.
lcs[0] = swap;
}
lcs[0] = lcs0;
}
length = lcs[size];
}
return length ;
}
=========== 与一般的计算LCS表的方法作对比 进行测试==============
public static void main(String[] args) {
Character[] x1 = new Character[201];
Character[] y1 = new Character[101];
x1[0] = '?';
y1[0] = '?';
// Randomly generate character of English letters in lower case.
for(int i=1;i<x1.length;i++){
char randomChar = (char)(97+(int)(Math.random()*26));
x1[i] = randomChar;
}
for(int i=1;i<y1.length;i++){
char randomChar = (char)(97+(int)(Math.random()*26));
y1[i] = randomChar;
}
int[][] bottom_lcsLength1 = new int[x1.length][y1.length];
dp_bottomUp_findLCSLength(x1,y1,bottom_lcsLength1);
// Test that findLCSLengthBy2Array() and findLCSLengthBy1Array() are correct.
System.out.println("The LCS length calculated by normal m*n table is " + bottom_lcs.length());
System.out.println("The LCS length calculated by 2*min(m,n) entries is "+ findLCSLengthBy2Array(x1, y1));
System.out.println("The LCS length calculated by min(m,n)+1 entries is "+findLCSLengthBy1Array(x1, y1));
}