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))


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM