package dynamicprogramming; /** * @author Eightn0 * @create 2021-03-30 10:48 * 分析: * LCS问题有两种,求两个字符串的最长公共序列、最长相同子串 * 若字符串A为"helloworld",字符串B为"lol",则AB的最长公共子序列为"lol",最长公共子串为"lo"。 * 对于字符串A和字符串B来说,设A的长度为lena,B的长度为lenb,A的第i个元素为i,B的第j个元素为j * 状态res[i,j]表示截至A的第i个元素和B的第j个元素的LCS结果 * 首先分析最长公共序列问题: * 若AB的长度任一为0,则无相同子序列,题意要求输出-1,即res[i,j]=-1; * 若AB的长度均不为0,若A的第i个元素和B的第j个元素相等,那么最长公共子序列的长度+1,即res[i,j]=res[i-1,j-1]+1 * 若A的第i个元素和B的第j个元素不相等,那么最长公共子序列则取决于上一个状态中的最大值,即res[i,j]=max(res[i,j-1],res[i-1,j]) * 然后分析最长相同子串问题: * 与最长公共序列不同的是,当寻找AB相同字符时中间出现断裂的时候,就停止本轮搜索了,题意保证str1和str2的最长公共子串存在且唯一,所以状态转移方程为 * res[i,j]=res[i-1,j-1]+1 * Java编程实现: * 对于最长公共序列问题,首先用二维数组描述状态和状态转移方程,用stringBuffer记录相同元素,倒序输出元素(这里也可以用栈)。 * 对于最长公共子串问题,仍然用二维数组描述状态和状态转移方程,但只要有长度和结束指针,内容可以用substring直接输出,无须另造stringbuffer */ public class LCS { /*给定两个字符串str1和str2,输出连个字符串的最长公共子序列。如过最长公共子序列为空,则输出-1。*/ public String LCS1 (String s1, String s2) { StringBuffer stringBuffer = new StringBuffer(); int lenA = s1.length(); int lenB = s2.length(); int[][] res = new int[lenA + 1][lenB + 1]; for (int i = 1; i < lenA + 1; i++) { for (int j = 1; j < lenB + 1; j++) { if (s1.charAt(i - 1) == s2.charAt(j - 1)){ res[i][j] = res[i - 1][j - 1] + 1; }else { res[i][j] = Math.max(res[i - 1][j], res[i][j - 1]); } } } while (lenA > 0 && lenB > 0) { if (s1.charAt(lenA - 1) == s2.charAt(lenB - 1)){ stringBuffer.append(s1.charAt(lenA - 1)); lenA --; lenB --; } else { if (res[lenA][lenB - 1] > res[lenA - 1][lenB]) {//找大的那个方向,此处是左边大于上面,则该处的结果是来自左边 lenB --; } else if (res[lenA][lenB - 1] < res[lenA - 1][lenB]) { lenA --; } else if (res[lenA][lenB - 1] == res[lenA - 1][lenB]) { lenB --; } } } if (stringBuffer.length() == 0) return "-1"; return stringBuffer.reverse().toString(); } /*给定两个字符串str1和str2,输出两个字符串的最长公共子串,题目保证str1和str2的最长公共子串存在且唯一。*/ public String LCS2 (String str1, String str2) { int max = 0; int end = 0; int lenA = str1.length(); int lenB = str2.length(); int[][] res = new int[lenA + 1][lenB + 1]; for (int i = 1; i < lenA + 1; i++) { for (int j = 1; j < lenB + 1; j++) { if (str1.charAt(i - 1) == str2.charAt(j - 1)){ res[i][j] = res[i - 1][j - 1] + 1; }else { res[i][j] = 0; } if (res[i][j] >= max){ max = res[i][j]; end=j-1; } } } if(max == 0){ return "-1"; }else{ return str2.substring(end - max + 1, end + 1); } } public static void main(String[] args) { String str1 = "helloworld"; String str2 = "lol"; LCS lcs = new LCS(); System.out.println(lcs.LCS2(str1, str2)); //System.out.println(lcs.LCS1(str1, str2)); } }
Java解决LCS问题
最新推荐文章于 2024-06-01 23:48:42 发布