1. 程式人生 > >【資料結構與演算法】最長公共子串 最長公共子序列

【資料結構與演算法】最長公共子串 最長公共子序列

1.最長公共子串:找出s和t的公共子字串的最大長度。

使用dp,定義子問題dp[i][j]:公共子串結束在位置i,j的長度。如果s[i] != t[j],那麼很顯然是0,否則dp[i][j] = dp[i - 1][j - 1] + 1。

程式碼:

public int longestCommonSubString(String s, String t){
		int[][] dp = new int[s.length()][t.length()];
		int max = 0;
		for(int i = 0; i < s.length(); i++){
			for(int j = 0; j < t.length(); j++){
				if(s.charAt(i) == t.charAt(j))
					dp[i][j] = 1 + ((i - 1 < 0 || j - 1 < 0)?0:dp[i - 1][j - 1]);
				else 
					dp[i][j] = 0;
				max = Math.max(dp[i][j], max);
			}
		}
		return max;
	}

2.最長公共子序列:找出s和t的公共子序列的最大長度,子序列不需要連續。

使用dp,定義子問題dp[i][j]:s[0-i]和t[0-j]的最長公共子序列長度。那麼首先可以利用之前的結論,即dp[i][j] = max(dp[i - 1][j] + dp[i][j - 1])無論什麼情況,dp[i][j]都等於這個。這是由於子序列的性質,大的範圍成立,小的範圍當然也成立。然後看如果s[i]=t[j],那麼還可以用dp[i - 1][j - 1] +1 來嘗試,dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1)。

程式碼:

	public int longestCommonSubSequence(String s, String t){
		int[][] dp = new int[s.length() + 1][t.length() + 1];
		for(int i = 1; i <= s.length(); i++){
			for(int j = 1; j <= t.length(); j++){
				dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
				if(s.charAt(i - 1) == t.charAt(j - 1))
					dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - 1] + 1);
			}
		}
		return dp[s.length()][t.length()];
	}

從這裡可以看出串和序列的區別。串要求連續,只要有一處不同就不能被後面的利用。但是序列不同,後面的總可以利用前面的結果。所以可以說串是遍歷所有的可能,而序列是遍歷所有的範圍。取最大時,串必須取所有可能的最大,而序列只需要看最大的範圍即可。