Leetcode-Longest Common Substring(最长公共子字符串)

Longest Common Substring 最长公共子字符串

动态规划问题

动态规划问题的两个特点:
1.最优子结构
2.重叠子问题
因为有重叠子问题,当前计算的过程中可能有的问题在之前的计算已经计算过了,现在又要计算一遍,导致大量重复的计算。
动态规划通过找到解决问题的递推关系,将已经完成计算的存储起来,
当开始新的计算时如果包含之前计算的子问题时,不需要再次计算,只需要访问已经存储的计算结果就可以,
这种方法减少了时间复杂度,增加了存储空间。

假设有两个字符串s[0,...m],t[0,...,n],求两个字符串的最长公共子字符串
定义矩阵mXn的矩阵L,L[i][j]表示以s[i]开始和t[j]结尾的公共子字符串长度的最大值
那么对于L[i+1][j+1]只是比L[i][j]增加了s[i+1]和t[j+1]
因此可以构造出最长公共子字符串的递归式:
if s[i]==t[j]
L[i][j]=L[i-1][j-1]+1
if s[i]!=t[j]
L[i][j]=0
假设有两个字符串:"ABAB"和"BABA" ,构造出了上述的矩阵

代码实现

    public static String LCS(String s1,String s2){
        if(s1.isEmpty() || s2.isEmpty()){
            return "";
        }
        int indexMax=0,maxn=0;
        int[][] L=new int[s1.length()][s2.length()];
        for(int i=0;i<s1.length();i++){
            for(int j=0;j<s2.length();j++){
                if(s1.charAt(i)==s2.charAt(j)){
                    if(i==0 || j==0){
                        L[i][j]=1;
                    }else{
                        L[i][j]=L[i-1][j-1]+1;
                    }
                }
                if(L[i][j]>maxn){
                    maxn=L[i][j];
                    indexMax=i;
                }
            }
        }
        return s1.substring(indexMax+1-maxn, indexMax+1);
    }  

算法分析:

时间复杂度:O(m*n)
空间复杂度:O(m*n)

算法优化

从上面动态查找最长公共子字符串的过程中发现,在循环查找的过程中只会用到矩阵L中的两行,即正在计算的一行和完成计算的上一行,之前计算的和带计算的都用不到,
所以只需要维护两行数据就足够了,不需要使用mxn的数组  

代码实现:

public class LCS_improve {
    public static String LCS_improve(String s1,String s2){
        if(s1.isEmpty() || s2.isEmpty()){
            return "";
        }
        int indexMax=0,maxn=0;
        int [][] L=new int[2][s1.length()];
        for(int i=0;i<s1.length();i++){
            int cur=(i+2)%2;
            int pre=(i+1)%2;
            for(int j=0;j<s2.length();j++){
                if(s1.charAt(i)==s2.charAt(j)){
                    if(i==0 || j==0){
                        L[cur][j]=1;
                    }else{
                        L[cur][j]=L[pre][j-1]+1;
                    }
                }else{
                    L[cur][j]=0;
                }
                if(L[cur][j]>maxn){
                    maxn=L[cur][j];
                    indexMax=i;
                }
            }
        }
        return s1.substring(indexMax+1-maxn, indexMax+1);
    }
}  

算法分析:

时间复杂度:O(mn)
空间复杂度:O(min(m,n))

猜你喜欢

转载自www.cnblogs.com/guolipa/p/10053551.html