15.4.3
自顶向下的DP,按照标准的memoized递归写法即可。代码如下:
public static <T> void dp_topDown_findLCSLength(T[] x,T[] y,int[][] lcsLength){ for(int i=0;i<y.length;i++){ lcsLength[0][i] =0; } for(int i=0;i<x.length;i++){ lcsLength[i][0] =0; } // Initialize the auxiliary table for(int i=1;i<x.length;i++){ for(int j=1;j<y.length;j++){ lcsLength[i][j] = -1; } } // Call the memoized-type recursive function that actually performs the task. memoized_findLCSLength(x, y, lcsLength, x.length-1, y.length-1); } private static <T> int memoized_findLCSLength(T[] x,T[] y,int[][] lcsLength,int i,int j){ if(lcsLength[i][j]>=0){ // Keep track of how many recursion calls are saved. savedRecursions++; return lcsLength[i][j]; }else{ int result = 0; if(x[i] == y[j]) result = memoized_findLCSLength(x, y, lcsLength, i-1, j-1) + 1; else{ result = Math.max(memoized_findLCSLength(x, y, lcsLength, i-1, j), memoized_findLCSLength(x, y, lcsLength, i, j-1)); } // Do not forget to update auxiliary table. lcsLength[i][j] = result; return result; }
public static <T> void dp_bottomUp_findLCSLength(T[] x,T[] y,int[][] lcsLength){ for(int i=0;i<y.length;i++){ lcsLength[0][i] =0; } for(int i=0;i<x.length;i++){ lcsLength[i][0] =0; } for(int i=1;i<x.length;i++){ for(int j=1;j<y.length;j++){ if(x[i] == y[j]){ lcsLength[i][j] = lcsLength[i-1][j-1] + 1; }else if(lcsLength[i-1][j] >= lcsLength[i][j-1]){ lcsLength[i][j] = lcsLength[i-1][j]; }else{ lcsLength[i][j] = lcsLength[i][j-1]; } } } }
findLCS用于查找一个具体的最优解:
// Get a concrete optimal solution. public static <T> String findLCS(int[][] lcsLength,T[] x,T[] y){ StringBuilder sb = new StringBuilder(); int i=x.length-1; int j=y.length-1; while(i>0 && j>0){ if(x[i] == y[j]){ sb.insert(0, x[i]); i = i-1; j = j-1; }else if(lcsLength[i-1][j] >= lcsLength[i][j-1]){ i = i -1; }else{ j = j-1; } } return sb.toString(); }
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]; int[][] top_lcsLength1 = new int[x1.length][y1.length]; dp_topDown_findLCSLength(x1, y1, top_lcsLength1); dp_bottomUp_findLCSLength(x1,y1,bottom_lcsLength1); String bottom_lcs = findLCS(bottom_lcsLength1,x1, y1); String top_lcs = findLCS(top_lcsLength1, x1, y1); // Test that bottom-up and top-down approaches get the same result. System.out.println("The longest common sequence found by bottom-up manner is " + bottom_lcs); System.out.println("The longest common sequence found by top-down manner is " + top_lcs); System.out.println("Are they the same? " + bottom_lcs.equals(top_lcs));}