【資料結構與演算法】最長公共子串 最長公共子序列
阿新 • • 發佈:2019-01-06
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()]; }
從這裡可以看出串和序列的區別。串要求連續,只要有一處不同就不能被後面的利用。但是序列不同,後面的總可以利用前面的結果。所以可以說串是遍歷所有的可能,而序列是遍歷所有的範圍。取最大時,串必須取所有可能的最大,而序列只需要看最大的範圍即可。