最长公共子序列与最长公共字串
显然最长公共子序列不一定需要连续的,只要字符的顺序严格递增即可。最长公共字串需要字符连续
子序列代码:
package test; import java.util.*; /* * 本题是求最长公共子序列,子序列未必连续,只需要严格递增即可 * 如 abcdeeeeeeeee和atttbggcd 最长公共子序列为abcd 长度为4 * * */ public class Main4{ public static void main(String... args){ try(Scanner in = new Scanner(System.in)){ while(in.hasNext()){ String s1 = in.nextLine(); String s2 = in.nextLine(); String min1 = s1.length() < s2.length()? s1 : s2; String max1 = s1.equals(min1) ? s2 : s1; //dp[i][j]表示i串和j串的最长公共字串 char[] min = min1.toCharArray(); char[] max = max1.toCharArray(); int[][] dp = new int[max.length+1][max.length+1]; for(int i = 1; i < min.length + 1;i++) { for(int j = 1; j < max.length + 1;j++) { if(min[i-1] == max[j-1]) { dp[i][j] = dp[i-1][j-1] + 1; }else { dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]); } } } for(int i = 0; i < min.length + 1; i++) { for(int j = 0; j < max.length + 1;j++) { if(j == max.length) System.out.println(dp[i][j]); else System.out.print(dp[i][j] + " "); } } System.out.println("++++++++++++++++++++"); int flag = 0; for(int i = 0; i < min.length + 1;i++) { for(int j = 0; j < max.length + 1; j++) { if(dp[i][j] == flag + 1) { System.out.print(max[j-1]); flag = dp[i][j]; } } } } } } }
最长公共字串代码
package test; import java.util.*; public class Main2{ public static void main(String... args){ try(Scanner in = new Scanner(System.in)){ while(in.hasNext()){ String s1 = in.nextLine(); String s2 = in.nextLine(); String min1 = s1.length() < s2.length()? s1 : s2; String max1 = s1.equals(min1) ? s2 : s1; //dp[i][j]表示i串和j串的最长公共字串 char[] min = min1.toCharArray(); char[] max = max1.toCharArray(); int[][] dp = new int[max.length+1][max.length+1]; for(int i = 1; i < min.length + 1;i++) { for(int j = 1; j < max.length + 1;j++) { if(min[i-1] == max[j-1]) { dp[i][j] = dp[i-1][j-1] + 1; } } } for(int i = 0; i < min.length + 1; i++) { for(int j = 0; j < max.length + 1;j++) { if(j == max.length) System.out.println(dp[i][j]); else System.out.print(dp[i][j] + " "); } } System.out.println("++++++++++++++++++++"); int flag = 0; int MAX = 0; int end = 0; for(int i = 1; i < min.length + 1;i++) { for(int j = 1; j < max.length + 1; j++) { if(dp[i][j] > MAX) { MAX = dp[i][j]; end = j; } } } System.out.println("MAX为:"+ MAX); System.out.println("end为:"+ end); for(int i = end - MAX ; i < end; i++) { if(i == end - 1) System.out.println(max[i]); else System.out.print(max[i]); } } } } }
仔细比对两处代码可知,公共子序列需要将每一次循环中记录子序列的结果,dp的值一直更新(虽然值有可能不变)。而公共字串只有当字符连续的时候,dp值才会发生更新。
公共子序列在输出结果时,我们可以先把状态矩阵打印出来,观察矩阵可知,当每组数据第一次发生变化,就是子序列的值。比如
当然,也可以纵向理解,则打印出min的第一次变化处的值即可。