最长公共子序列

对于最长公共字串问题,说一下自己的见解
对于最长公共子序列问题,首先考虑最后的字母,这里称第一个字符串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
自此最优子结构和重复子问题都已经证明了,递推公式就是

最长公共子序列_第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();
    }
}

你可能感兴趣的:(算法,动态规划)