参考的链接:https://blog.csdn.net/hrn1216/article/details/51534607

 // LCS(longest common sequence(还有另一种LCS,longest common string,中文名为最长公共子串,
    // 他和sequence的区别是,sequence不要求连续,string要求连续))
    public static String LCS(String s1, String s2) {
        int row = s1.length();
        int column = s2.length();
        //注意dp的长度问题,是s1.length+1与s2.length+1,为什么要加1呢,虽然s1,s2的索引范围为[0,row-1],[0,column-1]
        //但是要多记录一种情况即s1和s2为空字符串的情况,使用dp[i][0]与dp[0][j]来记录,那么肯定为0,dp[0][j]与dp[i][0]使用默认的0就行。
        //所以dp的行数范围为[0,row],列数范围为[0,column],比s1和s2的长度多1,即dp[i,j]表示s1长度为i-1,s2长度为j-1的最长公共子序列的长度,.
        int[][] dp = new int[row + 1][column + 1];
        for (int i = 1; i < row + 1; i++) {
            for (int j = 1; j < column + 1; j++) {
                //dp[i,j]表示s1长度为i-1,s2长度为j-1的最长公共子序列的长度,所以这里要比较s1.charAt(i - 1) == s2.charAt(j - 1)
                if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        //目前dp记录了s1和s2的最长子序列的长度
        //最长子序列长度为0时,按照题意输出-1;
        if(dp[row][column]==0) return "-1";
        // lcs用来储存结果数组
        char[] lcs = new char[dp[row][column]];
        // 因为要对dp倒着查看,所以lcs也倒着插入,cur表示当前插入的位置
        int cur = lcs.length - 1;
        /*
        插入的思想:
       若dp[8][9] = 5,且S1[7] != S2[8],所以倒推回去,dp[8][9]的值来源于dp[8][8]与dp[7][9]的值的最大值。根据情况让row-1或者column-1。
       若dp[8][9] = 5, 且S1[7] = S2[8], 所以倒推回去,dp[8][9]的值来源于 dp[7][8]。row-1且column-1。
       有种特殊情况:
       若dp[8][9] = 5,且S1[7] != S2[8] ,且dp[8][8] = c[7][9] 这种存在分支的情况,这里请都选择一个方向(之后遇到这样的情况,也选择相同的方向)。
       最长子序列的解不是唯一的,在每次遇到dp[8][9] = 5,且S1[7] != S2[8] ,且dp[8][8] = c[7][9]这种情况时,选择不同的方向就会造成不同的解。
       牛客的示例中是向左走,参考的算法的网站中是向上走的~怎么走都可以。
       */
        while (true) {
            // s1.charAt(row - 1) == s2.charAt(column - 1)时,就记录下当前的字符
            if (s1.charAt(row - 1) == s2.charAt(column - 1)) {
                //记录字符
                lcs[cur--] = s1.charAt(row - 1);
                //cur<0即意味着lcs已经填充完毕,直接return吧
                if (cur < 0) return new String(lcs);
                row--;
                column--;
            } else {
                // s1.charAt(row - 1) != s2.charAt(column - 1)时,就比较dp[row - 1][column] 和 dp[row][column - 1]
                // 这里用的是>而不是>=,所以dp[row - 1][column] ==dp[row][column - 1]时,走的是左边~
                if (dp[row - 1][column] > dp[row][column - 1]) {
                    //走上面,row--
                    row--;
                } else {
                    //走左面,column--
                    column--;
                }
            }
        }