回到最常见的字符串问题了,这里的找两个字符串的最长公共子串,要求在原字符串中是连续的。其实和上面两个问题一样,这里依旧可以用动态规划来求解,其实博主自己也不大擅长动态规划,但是可以仿照上面的思路来操作。我们采用一个二维矩阵来记录中间的结果。这个二维矩阵怎么构造呢?直接举个例子吧:"bab"和"caba",则数组如下:
b a b
c 0 0 0
a 0 1 0
b 1 0 1
a 0 1 0
我们看矩阵的斜对角线最长的那个就是我们找的最长公共子串。(反斜对角线,因为我们算法最后截取LCS是在String1中找的,即X轴方向找)
那怎么求最长的由1组成的斜对角线呢?可以做这样的操作:当要在矩阵是填1时让它等于其左上角元素加1。
b a b
c 0 0 0
a 0 1 0
b 1 0 2
a 0 2 0
这样矩阵中的最大元素就是 最长公共子串的长度。
在构造这个二维矩阵的过程中由于得出矩阵的某一行后其上一行就没用了,所以实际上在程序中可以用一维数组来代替这个矩阵(这样空间复杂度就降低了哈)。
JAVA实现代码如下:
package Findwork;
/**
* @author hadoop
* Longest Common Substring
*最长公共子串(LCS)问题 通过用s1和s2构建矩阵的方法来做
*/
public class LCSubstring {
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1="baba";
String s2="caba";
String res =LCS(s1, s2);
System.out.println(res);
}
//超找连个子串中的最长公共子串
public static String LCS(String str1, String str2)
{
//判断两个字符串是否为空
if(str1==null || str2 == null)
{ return null; }
if (str1.equals(" ") || str2.equals(" "))
{ return null; }
int xLen = str1.length(); // 将s1放在x轴方向 ,其串长度为列数clo,xlen
int yLen = str2.length(); // 将s2放在y轴方向 ,其串长度为行数row,ylen
int baseCow[]=new int [xLen]; //记录基础行
int curCow[] = new int [xLen]; //记录当前行
int maxLen =0; //记录最长子串长度,及当前矩阵中最大元素
int pos=0; //记录当前行最大元素的最大列数
char c=' ';
for (int i=0;i<yLen;i++) //遍历s2 ,Y 列方向
{
c =str2.charAt(i);
for(int j=0;j<xLen;j++) //比较S1,X行方向
{
if (c==str1.charAt(j))
{
//j为0时 第一列 没有左上角元素
if (j==0) {
curCow[j]=1;
}else {
//curCow[j]=curCow[j-1]+1; //这一句写错了
curCow[j]=baseCow[j-1]+1;
}
if (maxLen<curCow[j]) {
maxLen=curCow[j];
pos =j;
}
}
}
//每当s2中一个元素 比较完一次s1时 生成一个curRow , 将其赋给baseRow,然后清空
for (int k=0;k<xLen;k++)
{
baseCow[k]=curCow[k];
curCow[k]=0;
}
}
return str1.substring(pos+1-maxLen, pos+1); //substring c++和java 不同,java右边参数不包括, 记住这里找的是s1 , curRow找的是行
}
}