一、最长公共子序列问题(LCS问题)
我们首先需要搞清楚以下两个概念:最长公共子序列 VS 最长公共子串:
找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的。而最长公共子序列则并不要求连续。
问题描述:
给定两个字符串,求解这两个字符串的最长公共子序列(Longest Common Sequence)。比如字符串1:BDCABA;字符串2:ABCBDAB,则这两个字符串的最长公共子序列长度为4,最长公共子序列是:BCBA
动态规划解法分析:
设 A=(A1,A2,…An) 和 B={B1,B2,…Bm} 是两个序列,将 A 和 B的最长公共子序列记为LCS(A,B)
找出LCS(A,B)就是一个最优化问题。因为,我们需要找到A 和 B中最长的那个公共子序列。而要找A 和 B的LCS,首先考虑A的最后一个元素和B的最后一个元素。
- 如果 An=Bm,即X的最后一个元素与Y的最后一个元素相同,这说明该元素一定位于公共子序列中。因此,现在只需要找:LCS(An-1,Bm-1)
- 如果An != Bm,产生了两个子问题:LCS(An-1,Bm) 和 LCS(An,Bm-1),因为序列A 和 序列B 的最后一个元素不相等,那说明最后一个元素不可能是最长公共子序列中的元素。求解上面两个子问题,得到的公共子序列谁最长,那谁就是 LCS(A,B)。用数学表示就是:LCS=max{LCS(An-1,Bm),LCS(An,Bm-1)}
我们要求c[i] [j],先判断str1的第i个元素str2的第j个元素是否相同即判断str[i - 1]和 str[j -1]是否相同,如果相同它就是c[i - 1] [j- 1] +1,相当于在两个字符串都去掉一个字符时的最长公共子串再加 1;否则最长公共子串取c[i] [j-1]或c[i-1] [j]。
public class LCSequence { //求解str1 和 str2 的最长公共子序列 public static int LCS(String str1, String str2) { int[][] c = new int[str1.length() + 1][str2.length() + 1]; for (int row = 0; row <= str1.length(); row++) c[row][0] = 0; for (int column = 0; column <= str2.length(); column++) c[0][column] = 0; for (int i = 1; i <= str1.length(); i++) for (int j = 1; j <= str2.length(); j++) { if (str1.charAt(i - 1) == str2.charAt(j - 1)) c[i][j] = c[i - 1][j - 1] + 1; else c[i][j] = c[i][j - 1] > c[i - 1][j] ? c[i][j - 1] : c[i - 1][j]; } return c[str1.length()][str2.length()]; } //test public static void main(String[] args) { String str1 = "BDCABA"; String str2 = "ABCBDAB"; int result = LCS(str1, str2); System.out.println(result); } }
二、最长公共子串问题(LCS问题)
我们要求c[i] [j],先判断str1的第i个元素str2的第j个元素是否相同即判断str[i - 1]和 str[j -1]是否相同,如果相同它就是c[i - 1] [j- 1] +1,相当于在两个字符串都去掉一个字符时的最长公共子串再加 1;否则最长公共子串取0。
public class LongestSubstring { //求解str1 和 str2 的最长公共子串 public static int findLongest(String str1, String str2) { int[][] c = new int[str1.length() + 1][str2.length() + 1]; for (int row = 0; row <= str1.length(); row++) c[row][0] = 0; for (int column = 0; column <= str2.length(); column++) c[0][column] = 0; int res = 0; for (int i = 1; i <= str1.length(); i++) for (int j = 1; j <= str2.length(); j++) { if (str1.charAt(i - 1) == str2.charAt(j - 1)){ c[i][j] = c[i - 1][j - 1] + 1; res = Math.max(res, c[i][j]); } else c[i][j] = 0; } return res; } //test public static void main(String[] args) { String str1 = "HelloWorld"; String str2 = "loop"; int result = LCS(str1, str2); System.out.println(result); } }