最长公共子串

最长公共子串

​ 给定两个字符串str1和str2,返回两个字符串的最长公共子串。

此处计算的是两个字符串的最长公共子串,子串不同于子序列,子串要求必须是一串连续的字符。

方法一

​ 使用经典的动态规划方法,首先定义一个动态规划数组dp,dp[i][j]表示的含义是以在str1中第i个字符和str2中第j个字符结尾的最长公共字串的长度。那么状态转移表达式就是:

​ 1、如果str1[i] == str2[j]

dp[i][j] = dp[i-1][j-1] + 1;

​ 2、如果str1[i] != str2[j]

dp[i][j] = 0

初始化:

​ 对于dp[i][0],如果str1[i] == str2[0],则dp[i][0] = 1;

​ 对于dp[0][j],如果str1[0] == str2[j],则dp[0][j] = 1;

public static int longestCommonStr(String text1, String text2){

    int n = text1.length();
    int m = text2.length();

    int[][] dp = new int[n][m];
    int max_length = 0;
    for (int i = 0; i < text1.toCharArray().length; i++) {

        if (text1.charAt(i) == text2.charAt(0)){
            dp[i][0] = 1;
            max_length = 1;
        }
    }
    for (int j = 0;j < text2.toCharArray().length;j++){

        if (text2.charAt(j) == text1.charAt(0)){
            dp[0][j] = 1;
        }
    }
    for (int i = 1; i < n; i++) {

        for (int j = 1; j < m; j++) {

            if (text1.charAt(i) == text2.charAt(j)){
                dp[i][j] = dp[i-1][j-1] + 1;
            }else {
                dp[i][j] = 0;
            }
            max_length = max_length>dp[i][j]?max_length:dp[i][j];
        }

    }
    return max_length;
}

​ 时间复杂度为O(n*m),空间复杂度为O(n*m)

方法二

​ 优化上面算法的空间复杂度,将其由O(n*m)优化为常量级别的O(1)

​ 在上面,我们定义的状态转移数组,是一个二维矩阵,其中每一个元素代表的含义就是以在str1中第i个字符和str2中第j个字符结尾的最长公共字串的长度,而dp[i][j]的值要么是0,要么就是在状态转移矩阵其位置的左上方的那个值的基础上加1得到。

​ 比如字符串 "abcde" 和 "bebcd",它的状态转移矩阵是:

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

​ 如果按照上图中的斜线来计算的话,那么就无需再使用状态转移数组,而只需变量就可以了。

​ 在按照斜线进行计算之前,先定义一个变量len,它用于记录状态转移矩阵中当前位置的左上方位置的值,初始值为0,计算的过程中首先判断if str1[i] == str2[j]:

​ 如果相等,那么len++;否则len=0

​ 我们从右上方的斜线开始计算,然后依次向左移动,计算左边的斜线;当无法向左移动的时候,再向下移动,当最左下方的斜线计算完毕以后,整个计算就完毕了。

public static int longestCommonStr2(String text1, String text2){

    int m = text1.length();
    int n = text2.length();

    int row = 0;
    int col = n - 1;
    int max_length = 0;

    while (row < m){
        int i = row;
        int j = col;
        int len = 0;
        while (j < n && i < m){

            if (text1.charAt(i) == text2.charAt(j)){
                len++;
            }else {
                len = 0;
            }
            j++;
            i++;
        }
        max_length = max_length > len ? max_length : len;

        if (col > 0){
            col--;
        }else {
            row++;
        }
    }

    return max_length;

}

​ 此算法的空间复杂度为O(1)

posted @ 2021-02-19 14:48  有心有梦  阅读(759)  评论(0编辑  收藏  举报