题目描述:
两个字符串如"programming"和"contest"的最长公共子序列为“on”,长度为2;
“abcd”和"mnp"的最长公共子序列为"",长度为0;
"bcdb"和“abcbdab”的最长公共子串为“bcdb”,长度为4;
注:相应的下标必须递增。如"bcdb"对应“abcbdab”的下标为{2,3,5,7};
递推关系:
设序列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的最长公共子序列。
其中,Xm-1={x1,x2……xm-1},Yn-1={y1,y2……yn-1},Zk-1={z1,z2……zk-1}。
转自:http://blog.youkuaiyun.com/liufeng_king/article/details/8500084
构造最优解:由以上分析可知,要找出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的最长公共子序列。设数组path[i][j]记录matrix[i][j]的值由哪一个子问题的解得到的,从path[m][n]开始,依其值在数组b中搜索,当path[i][j]=1时,表示Xi和Yj的最长公共子序列是由Xi-1和Yj-1的最长公共子序列在尾部加上xi所得到的子序列。当path[i][j]=2时,表示Xi和Yj的最长公共子序列与Xi-1和Yj的最长公共子序列相同。当path[i][j]=3时,表示Xi和Yj的最长公共子序列与Xi和Yj-1的最长公共子序列相同。
//递归方法
public int maxLen(String str1,String str2,int i,int j)
{
if(i==0||j==0)//i,j表示前i个字符构成的子串和前j个字符构成的子串;
{
return 0;
}
if(str1.charAt(i-1)==str2.charAt(j-1))//字符下标从0开始;
return maxLen(str1,str2,i-1,j-1)+1;
else
{
if(maxLen(str1,str2,i-1,j)>maxLen(str1,str2,i,j-1))//两个序列的i和j不是同时增减的关系,只表示两个序列的长度;
return maxLen(str1,str2,i-1,j);
else
return maxLen(str1,str2,i,j-1);
}
}
//DP_自底向上的方式;matrix[m][n]存放长度为m和n的字符串的最长子串值;
public int maxLen_DP(String str1,String str2,int m,int n)
{
int [][]matrix=new int [m+1][n+1];//自底向上循环方式数组定义在内部;
//m==0或n==0时,matrix[m][n]=0;
for(int i=1;i<=m;i++)//两层for循环;
{
for(int j=1;j<=n;j++)
{
if(str1.charAt(i-1)==str2.charAt(j-1))
{
matrix[i][j]=matrix[i-1][j-1]+1;
path[i][j]=1;
}
else
{
if(matrix[i][j-1]>matrix[i-1][j])
{
matrix[i][j]=matrix[i][j-1];
path[i][j]=2;
}
else
{
matrix[i][j]=matrix[i-1][j];
path[i][j]=3;
}
}
}
}
return matrix[m][n];
}
//构造最优解,用一个矩阵path存放路径;
//进行不同的路径选择时分别设为状态1,2,3;
int [][]path=new int[13][13];
//构造最优解的函数;
public void LCS(String str1,int [][]path,int i,int j)
{
if(i==0||j==0)
return;
if(path[i][j]==1)
{
LCS(str1,path,i-1,j-1);
System.out.print(""+str1.charAt(i-1));
}
else if(path[i][j]==3)
{
LCS(str1,path,i-1,j);
}else if(path[i][j]==2)
{
LCS(str1,path,i,j-1);
}
}