第二种:动态规划
思路: 二维数组, 下图:str1: sabgc ,s2:abcg, 二维数组,相同的标记为1 ,不同的标0,可以看出斜对角为1 的就是最长的字串。第一个一样标记1, 第二个对角相同,值应该是x,y下标-1 的值在+1,记录的就是长度。
图片说明
为了让递推公式dp[i][j] = dp[i-1][j-1] + 1;成立,所以应多初始化一行一列dp[0][0],相当于在图片外层又包裹一行一列的0
图片说明
红色部分为新增的一行一列的初始化dp
黄色部分为数组下标偏移1位
这样在推到dp[1][0]的时候 就可以通过刚刚新增的dp初始化红色部分数组的值0,来推出其值为左上角位置+1

import java.util.*;


public class Solution {
    /**
     * longest common substring
     * @param str1 string字符串 the string
     * @param str2 string字符串 the string
     * @return string字符串
     */
    public String LCS (String str1, String str2) {

        if (str1 == null || str2 == null || str1.length() == 0 || str2.length() == 0) {
            return "-1";
        }

        //动态规划  二维数组,斜下来就是最长字串
        int str1Len = str1.length();

        int str2Len = str2.length();

        //记录最长公共子串长度
        int maxLen = 0;

        //记录最长子串最后一个字符的下标
        int index = 0;

        //这里+1 是为了让dp[i][j] = dp[i-1][j-1] + 1;递推公式成立,单独多出一行一列dp[0][0]供递推公式计算
        int[][] dp = new int[str1Len + 1][str2Len + 1];

        //str1为行坐标
        for (int i = 1; i <= str1Len; i++) {

            //str2为列坐标
            for (int j = 1; j <= str2Len; j++) {

                //这里的i-1 j-1意味着是字符串的第一个字符,而非dp[0][0]这个第一列
                if (str1.charAt(i-1) == str2.charAt(j-1)) {
                   //str1 str2的该位置字符如果相等,那么用上一个斜上角位置的元素进行+1 可获取当前公共子串的长度
                   dp[i][j] = dp[i-1][j-1] + 1;
                } else {
                    dp[i][j] = 0;
                }

                if (maxLen < dp[i][j]) {
                    maxLen = dp[i][j];
                    //因为不能算dp[0] 所以以上循环都是从1开始的 这里要减去1
                    index = i-1;
                }
            }
        }

        if (maxLen == 0) {
            return "-1";
        }

        return str1.substring(index - maxLen + 1, index + 1);
    }
}