最长公共子序列(LCS)

问题描述
子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串算法

  • cnblogs
  • belong

好比序列bo, bg, lg在母串cnblogs与belong中都出现过而且出现顺序与母串保持一致,咱们将其称为公共子序列。最长公共子序列(Longest Common Subsequence,LCS),顾名思义,是指在全部的子序列中最长的那一个。子串是要求更严格的一种子序列,要求在母串中连续地出现。在上述例子的中,最长公共子序列为blog(cnblogs,belong),最长公共子串为lo(cnblogs, belong)。
求解算法
对于母串X=<x1,x2,⋯,xm>, Y=<y1,y2,⋯,yn>,求LCS与最长公共子串。
假设Z=<z1,z2,⋯,zk>是X与Y的LCS, 咱们观察到:
- 若是Xm=Yn,则Zk=Xm=Yn,有:Zk−1是Xm−1与Yn−1的LCS;
- 若是Xm≠Yn,则Zk是Xm与Yn−1的LCS,或者是Xm−1与Yn的LCS。数组

所以,求解LCS的问题则变成递归求解的两个子问题。可是,上述的递归求解的办法中,重复的子问题多,效率低下。改进的办法——用空间换时间,用数组保存中间状态,方便后面的计算。这就是动态规划(DP)的核心思想了。
DP求解LCS
用二维数组c[i][j]记录串x1,x2,⋯,xi与y1,y2,⋯,yj的LCS长度,则可获得状态转移方程:

由最长公共子序列问题的最优子结构性质可知,要找出X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的最长公共子序列,可按如下方式递归地进行:当xm=yn时,找出Xm-1和Yn-1的最长公共子序列,而后在其尾部加上xm(=yn)便可得X和Y的一个最长公共子序列。当xm≠yn时,必须解两个子问题,即找出Xm-1和Y的一个最长公共子序列及X和Yn-1的一个最长公共子序列。这两个公共子序列中较长者即为X和Y的一个最长公共子序列。
在算法LCS中,每一次的递归调用使i或j减1,所以算法的计算时间为O(m+n)
代码实现spa

 1 int lcs(String str1, String str2) {
 2 int len1 = str1.length();
 3 int len2 = str2.length();
 4 int c[][] = new int[len1 + 1][len2 + 1];
 5 for (int i = 0; i <= len1; i++) {
 6 for (int j = 0; j <= len2; j++) {
 7 if (i == 0 || j == 0) {
 8 c[i][j] = 0;
 9 } else if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
10 c[i][j] = c[i - 1][j - 1] + 1;
11 } else {
12 c[i][j] = max(c[i - 1][j], c[i][j - 1]);
13 }
14 }
15 }
16 return c[len1][len2];
17 }
相关文章
相关标签/搜索