lcs算法

LCS问题就是求两个字符串最长公共子串的问题。解法就是用一个矩阵来记录两个字符串中所有位置的两个字符之间的匹配情况,若是匹配则为1,否则为0。然后求出对角线最长的1序列,其对应的位置就是最长匹配子串的位置。

下面是字符串21232523311324和字符串312123223445的匹配矩阵,前者为X方向的,后者为Y方向的。不难找到,红色部分是最长的匹配子串。通过查找位置我们得到最长的匹配子串为:21232


0 0 0 1 0 0 0 1 1 0 0 1 0 0 0
0 1 0 0 0 0 0 0 0 1 1 0 0 0 0
1 0 1 0 1 0 1 0 0 0 0 0 1 0 0
0 1 0 0 0 0 0 0 0 1 1 0 0 0 0
1 0 1 0 1 0 1 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 1 0 0 1 0 0 0
1 0 1 0 1 0 1 0 0 0 0 0 1 0 0
1 0 1 0 1 0 1 0 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1 1 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0


但是在0和1的矩阵中找最长的1对角线序列又要花去一定的时间。通过改进矩阵的生成方式和设置标记变量,可以省去这部分时间。下面是新的矩阵生成方式:


0 0 0 1 0 0 0 1 1 0 0 1 0 0 0
0 1 0 0 0 0 0 0 0 2 1 0 0 0 0
1 0 2 0 1 0 1 0 0 0 0 0 1 0 0
0 2 0 0 0 0 0 0 0 1 1 0 0 0 0
1 0 3 0 1 0 1 0 0 0 0 0 1 0 0
0 0 0 4 0 0 0 2 1 0 0 1 0 0 0
1 0 1 0 5 0 1 0 0 0 0 0 2 0 0
1 0 1 0 1 0 1 0 0 0 0 0 1 0 0
0 0 0 2 0 0 0 2 1 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0


不用多说,你大概已经看出来了。当字符匹配的时候,我们并不是简单的给相应元素赋上1,而是赋上其左上角元素的值加一。我们用两个标记变量来标记矩阵中值最大的元素的位置,在矩阵生成的过程中来判断当前生成的元素的值是不是最大的,据此来改变标记变量的值,那么到矩阵完成的时候,最长匹配子串的位置和长度就已经出来了。

这样做速度比较快,但是花的空间太多。我们注意到在改进的矩阵生成方式当中,每生成一行,前面的那一行就已经没有用了。因此我们只需使用一维数组即可。最终的代码如下:

Private Function LCS(ByVal str_1 As String, ByVal str_2 As String) As String
If str_1 = "" Or str_2 = "" Then Return ""

Dim c(str_1.Length) As Integer
Dim max, maxj, i, j As Integer
maxj = 0 : max = 0 '这两个是标志变量
For i = 0 To str_2.Length - 1
For j = str_1.Length - 1 To 0 Step -1
If str_2.Chars(i) = str_1.Chars(j) Then
If i = 0 Or j = 0 Then
c(j) = 1
Else
c(j) = c(j - 1) + 1
End If
Else
c(j) = 0
End If
If c(j) > max Then '把>改成>=则返回最后一个最长匹配子串
max = c(j) : maxj = j '更新标志变量
End If
Next
Next

If max = 0 Then Return ""
Return str_1.Substring(maxj - max + 1, max) '直接从标志变量得出结果
End Function
### LCS算法概述 最长公共子序列(Longest Common Subsequence, LCS)用于寻找两个给定序列共有的最小子序列,该子序列不必连续。此问题常采用动态规划方法解决,在实际应用中广泛应用于文件差异比较工具、生物信息学等领域。 #### 动态规划求解LCS长度 定义`c[i][j]`表示序列`(x1,x2,...,xi)`和`(y1,y2,...,yj)`的最长公共子序列长度[^2]。对于任意一对索引i和j: - 如果`xi == yj`,那么`c[i][j]= c[i−1][j−1]+1`; - 否则取较大者作为当前状态的结果:`c[i][j]=max(c[i−1][j],c[i][j−1])`. 这种递推关系反映了LCS具备最优子结构特性——即整体解决方案由局部最优方案构成[^4]. ```java public static int lcsLength(char[] X, char[] Y){ int m = X.length; int n = Y.length; int[][] C = new int[m+1][n+1]; for(int i=0; i<=m ;++i) for(int j=0;j<=n;++j){ if(i==0 || j==0) C[i][j]=0; else if(X[i-1]==Y[j-1]) C[i][j]=C[i-1][j-1]+1; else C[i][j]=Math.max(C[i-1][j],C[i][j-1]); } return C[m][n]; } ``` 上述代码实现了计算两个字符数组之间最大公共子串长度的功能[^1]. #### 输出一个可能的LCS路径 除了获取LCS长度外,还可以基于构建好的表逆向追踪得到至少一条符合条件的具体路径: ```java private static void printOneLCS(StringBuilder sb,char[] X,int[][] b,int i ,int j ){ while(i>0 && j>0){ if(b[i][j]==DIAGONAL){ // DIAGONAL is a constant representing diagonal move --i; --j; sb.append(X[i]); }else{ if(b[i][j]==UPWARD)--i;// UPWARD represents upward movement else--j; // otherwise it's LEFTWARDS which means moving leftward. } } } // Note that this function should be called after filling up the table 'b' during length calculation phase. ``` 这段逻辑能够帮助打印出从右下角到左上角的一条有效路径,从而获得一组满足条件的LCS实例[^3].
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值