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))
posted @ 2018-12-02 15:07  class0基础  阅读(2174)  评论(0编辑  收藏  举报