最长公共子串问题
【题目】
给定两个字符串str1和str2,返回两个字符串的最长公共子串。
【举例】str1="1AB2345CD",str2="12345EF",返回"2345"。
首先需要生成动态规划表。生成大小为M×N的矩阵dp,行数为M,列数为N。
dp[i][j]的含义是,在必须把str1[i]和str2[j]当作公共子串最后一个字符的情况下,公共子串最长能有多长。
比如,str1="A1234B",str2="CD1234",
dp[3][4]的含义是在必须把str1[3](即’3')和str2[4](即’3')当作公共子串最后一个字符的情况下,
公共子串最长能有多长。这种情况下的最长公共子串为"123",所以dp[3][4]为3。
]再如,str1="A12E4B",str2="CD12F4",
dp[3][4]的含义是在必须把str1[3](即’E')和str2[4](即’F')当作公共子串最后一个字符的情况下,
公共子串最长能有多长。这种情况下根本不能构成公共子串,所以dp[3][4]为0。介绍了dp[i][j]的意义后,
接下来介绍dp[i][j]怎么求。
具体过程如下:
1.矩阵dp第一列即dp[0..M-1][0]。
对某一个位置(i,0)来说,如果str1[i]==str2[0],令dp[i][0]=1,否则令dp[i][0]=0。
比如str1="ABAC",str2[0]="A"。
dp矩阵第一列上的值依次为dp[0][0]=1,dp[1][0]=0,dp[2][0]=1,dp[3][0]=0。
2.矩阵dp第一行即dp[0][0..N-1]与步骤1同理。对某一个位置(0,j)来说,
如果str1[0]==str2[j],令dp[0][j]=1,否则令dp[0][j]=0。
3.其他位置按照从左到右,再从上到下来计算,dp[i][j]的值只可能有两种情况。
● 如果str1[i]!=str2[j],说明在必须把str1[i]和str2[j]当作公共子串最后一个字符是不可能的,令dp[i][j]=0。
● 如果str1[i]==str2[j],说明str1[i]和str2[j]可以作为公共子串的最后一个字符,
从最后一个字符向左能扩多大的长度呢?就是dp[i-1][j-1]的值,所以令dp[i][j]=dp[i-1][j-1]+1。
如果str1="abcde",str2="bebcd"。计算的dp矩阵如下:
b e b c d
a 0 0 0 0 0
b 1 0 1 0 0
c 0 0 0 2 0
d 0 0 0 0 3
e 0 1 0 0 0
public static String getdp2(char[] str1,char[] str2){
if(str1==null||str2==null||str1.length==0||str1.length==0){
return "";
}
int m=str1.length;
int n=str2.length;
//dp[i][j]对应,如果str1[i]==str2[j],以str1[i]为最后一个字符的情况下的最长公共子串,否则为0
int[][] dp=new int [m][n];
//初始化dp[0][0]
dp[0][0]=(str2[0]==str1[0])?1:0;
//初始化第一行
for (int i = 1; i < n; i++) {
if(str1[0]==str2[i]){
dp[0][i]=1;
}
}
//初始化第一列
for (int i = 1; i < m; i++) {
if(str2[0]==str1[i]){
dp[i][0]=1;
}
}
//计算dp[i][j]
for (int i = 1; i < m; i++) {
for (int j = 1; j <n; j++) {
if(str1[i]==str2[j]){
dp[i][j]=dp[i-1][j-1]+1;
}
}
}
//以上可以得到一个二维数组dp
int endIndex=0;
int max=0;
//然后遍历数组获取最长公共子串
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if(dp[i][j]>max){
endIndex=i;
max=dp[i][j];
}
}
}
String result=String.copyValueOf(str1).substring(endIndex-max+1, endIndex+1);
return result;
}
测试:
public static void main(String[] args) {
//String s1="1a2c3d4b56";
//String s2="b1d23ca45b6a";
String s1="1ab2345cd";
String s2="12345ef";
char[] str1=s1.toCharArray();
char[] str2=s2.toCharArray();
//System.out.println(getdp(str1, str2));
System.out.println(getdp2(str1, str2));
}
2345