第11章:最长公共子序列(LCS:Longest Common Subsequence)

方法:动态规划 《算法导论》P208

最优子结构 + 重叠子问题

 

设xi,yi,为前i个数(前缀)

设c[i,j]为xi,yi的LCS的长度

 

c[i,j] = 0 (i ==0 || j == 0)

c[i,j] = a[i-1,j-1] + 1 (i,j>0 &&xi=yi)

c[i,j] = max(c[i,j-1],c[i-1,j])

 

 

 

 

 

求LCS(Xm-1 , Y)的长度与LCS(X , Yn-1)的长度,这两 个问题不是相互独立的:两者都需要求LCS(Xm-1,Yn-1)的长度。

 

【最长公共子序列的结构】

设序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的一个最长公共子序列Z=<z1, z2, …, zk>,

则:

1. 若xm=yn,则zk=xm=yn 且Zk-1 是Xm-1 和Yn-1 的最长公共子序列;

2. 若xm≠yn 且zk≠xm ,则Z 是Xm-1 和Y 的最长公共子序列;

3. 若xm≠yn 且zk≠yn ,则Z 是X 和Yn-1 的最长公共子序列。

 

由此递归结构容易看到最长公共子序列问题具有子问题重叠性质。

 

 

 

由于在所考虑的子问题空间中,总共只有θ(m*n)个不同的 子问题,因此,用动态规划算法自底向上地计算最优值能提高算法的效率。

 

【编码实现】

输出两个数组c[0..m ,0..n]和b[1..m ,1..n]。其中c[i,j]存储

Xi 与Yj 的最长公共子序列的长度,b[i,j]记录指示c[i,j]的值是由哪一个子问题的解达到的,

这在构造最长公共子序列时要用到。最后,X 和Y 的最长公共子序列的长度记录于c[m,n]

中。

 

【相似的解决方法:构造矩阵】

 

 

import java.util.Random;

 

public class LCS{

 public static void main(String[] args){

  int substringLength1 = 20;

  int substringLength2 = 20;

 

  String x = GetRandomStrings(substringLength1);

  String y = GetRandomStrings(substringLength2);

 

  Long startTime = System.nanoTime();

 

  int[][] opt = new int[substringLength1 + 1][substringLength2 + 1];

 

  for(int i = substringLength1 - 1;i>=0;i--){

   for(int j =substring2 -1;j>=0;j--){

    if(x.charAt(i) =  y.charAt(j))

     opt[i][j] = opt[i+1][j+1] + 1;

    else

     opt[i][j] = Math.max(opt[i+1][j],opt[i][j+1]);

   }

  }

 

  System.out.println("substring1:"+x);

  System.out.println("substring2:"+y);

  System.out.print("LCS:");

  int i = 0, j = 0;

  while (i < substringLength1 && j < substringLength2){

   if (x.charAt(i) == y.charAt(j)){

    System.out.print(x.charAt(i));

    i++;

    j++;

   } else if (opt[i + 1][j] >= opt[i][j + 1])

     i++;

   else

   j++;

  }

  Long endTime = System.nanoTime();

 

 }

}

posted @ 2015-09-26 23:13  Uncle_Nucky  阅读(136)  评论(0编辑  收藏  举报