对于最长公共字串问题,说一下自己的见解
对于最长公共子序列问题,首先考虑最后的字母,这里称第一个字符串s1第二个字符串s2。
dp[i][j]表示str1的前i个字母和str2前j个字母组成的子问题最长公共子串的长度。例如ACD,AD,dp[3][2]=2.
假设我们已经找到了最优解R,那么对于R来说无非就是四种情况
(1)包括s1的最后一个,但不包括s2的最后一个
(2)包括s2的最后一个但不包括s1的最后一个
(3)两个都包括
(4)两个都不包括,
情况就是这么多,接下来就要想每种情况出现的条件是什么。(3)的条件就是s1和s2的最后一个相等,因为只有相等时才会包括,那么对于(1)(2)(4)显而易见就是不相等,这里面还有一种特殊的情况就是(4),因为我们可以发现(4)这个问题是子问题的子问题,为什么这么说呢,因为如果出现了第一种(1)情况,那么子问题就是s1,s2减去最后一个字母组成的两个子串的最长公共子串问题,然后又出现了第(2)情况,那么子问题又变成了s1减去最后一个与s2减去最后一个,这两个子串组成的最优解问题,那么此时就是和(4)一样了,因此我们可以在算法中不去计算(4)因为我们在子问题中已经算出来了
接下来就是最优子结构了:如果出现了情况(1),那么R就是他的子问题的最优解(s1,s2减去最后一个字母组成的两个子串的最长公共子串问题)假设R才是子问题的最优解即length(R)>length®
这样就与R是最优解的假设背道而驰,显然R*不是最优解,那么递归公式就是dp[i][j]=dp[i-1][j]。
对于情况(2)推论是一样的dp[i][j]=dp[i][j-1],
接下来讨论(3),R包括最后一个字母那么此时R肯定不是他的子问题(s1-{end},s2-{end})[//end表示s1,s2的最后一个字母]的最优解了,但是R-{end}确实是子问题的最优解,证明:设R是子问题的最优解,那么便有length(R)>length®-1,然后因为最优解包括最后一个字母所以R*+1才是全部问题的最优解,这样与R是最优解背道而驰,递推公式dp[i][j]=d[i-1][j-1]+1
自此最优子结构和重复子问题都已经证明了,递推公式就是
代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class MaxPublicSub {
static String str1="";//第一个字符串
static String str2="";//第二个字符串
static ArrayList< ArrayList<Integer> > dp=new ArrayList<>();//存储最优解
private static int maxSub(){
Scanner scanner=new Scanner(System.in);
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(System.in));
try {
str1=bufferedReader.readLine();
str2=bufferedReader.readLine();
} catch (IOException e) {
System.out.println("error");
// throw new RuntimeException(e);
}
/*
* 初始化dp最优解数组
* */
for (int i = 0; i < str1.length()+1; i++) {
ArrayList<Integer> row = new ArrayList<>();
for (int j = 0; j < str2.length()+1; j++) {
row.add(0);
}
dp.add(row);
}
/*
* 求解过程
* */
for (int i = 1; i < str1.length()+1; i++) {
ArrayList<Integer> row = new ArrayList<>();
for (int j = 1; j < str2.length()+1; j++) {
if(str1.charAt(i-1)==str2.charAt(j-1)){//如果相等最优解加一
dp.get(i).set(j,dp.get(i-1).get(j-1)+1);
}else {//不相等就选择两个子问题的最优解的最大值
if(str1.charAt(i-1)!=str2.charAt(j-1)){
int max=Math.max(dp.get(i).get(j-1),dp.get(i-1).get(j));
dp.get(i).set(j,max);
}
}
}
}
return dp.get(str1.length()).get(str2.length());
}
private static void constructOptimumResolve(){
ArrayList<Character> arrayList=new ArrayList<>();
int i=str1.length();
int j=str2.length();
while (i>0&&j>0)
{
if(str1.charAt(i-1)==str2.charAt(j-1)){
arrayList.add(str1.charAt(i-1));
i--;j--;
}else {
int max=dp.get(i).get(j-1)>dp.get(i-1).get(j)?1:0;
if(max==1){
j--;
}
if(max==0){
i--;
}
}
}
for(int stri=arrayList.size()-1;stri>=0;stri--){
System.out.print(arrayList.get(stri));
}
}
public static void main(String[] args) {
System.out.println(maxSub());
constructOptimumResolve();
}
}