版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/afei__/article/details/83153399
一、最长公共子串
1. 题目
给定两个序列 X 和 Y,如果 Z 即是 X 的子串,又是 Y 的子串,我们就称它是 X 和 Y 的公共子串,注意子串是连续的。
例如 X = { A, B, C, D, E, F, G },Y = { A, B, Z, D, E, F, K, G },那么它们最长的公共子串即 { D, E, F }
2. 思路
借助一下《图解算法》中的例子。假设对于两个字符串 fish
和 hish
,我们可以绘制一个这样的表格,来求解它们最长的公共子串,即:
注意,最长公共子串的最终答案并不一定在最后一个格子里,所以我们还需要一个变量 max 来记录最大值。
3. 代码
public class Main {
public static void main(String[] args) {
String s1 = "ABCDEFG";
String s2 = "ABZDEFKG";
System.out.println("最长公共子串长度:" + getLCS(s1, s2));
}
public static int getLCS(String s1, String s2) {
char[] a = s1.toCharArray();
char[] b = s2.toCharArray();
// a.length行,b.length列
int[][] result = new int[a.length + 1][b.length + 1];
int max = 0;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < b.length; j++) {
if (a[i] == b[j]) {
result[i + 1][j + 1] = result[i][j] + 1;
max = Math.max(max, result[i + 1][j + 1]);
}
}
}
// ----- print table -----
System.out.print(" ");
for (int i = 0; i < b.length; i++) {
System.out.print(" " + b[i]); // 打印第一行
}
System.out.println();
for (int i = 1; i < result.length; i++) {
System.out.print(a[i - 1] + " ");
for (int j = 1; j < result[i].length; j++) {
System.out.print(result[i][j] + " ");
}
System.out.println();
}
System.out.println();
// -----------------------
return max;
}
}
注意上面代码中 print table
打印部分仅是为了给大家展示表格帮助理解,实际中并不需要。
执行结果:
A B Z D E F K G
A 1 0 0 0 0 0 0 0
B 0 2 0 0 0 0 0 0
C 0 0 0 0 0 0 0 0
D 0 0 0 1 0 0 0 0
E 0 0 0 0 2 0 0 0
F 0 0 0 0 0 3 0 0
G 0 0 0 0 0 0 0 1
最长公共子串长度:3
如果我们还需要知道具体的最长公共子串是什么,那么就需要再添加一个变量,记录最大值出现的位置,然后往前取最长公共子串的长度即可。
二、最长公共子序列
1. 题目
和最长公共子串类似,只不过子序列是可以不连续的。
例如 X = { A, B, C, D, E, F, G },Y = { A, B, Z, D, E, F, K, G },那么它们最长的公共子串即 { A, B, D, E, F, G }
2. 思路
还是借鉴一下《图解算法》里的例子吧,表格绘制过程如下:
注意最长公共子序列的话,最大值一定会出现在最后一个格子里。
3. 代码
public class Main {
public static void main(String[] args) {
String s1 = "ABCDEFG";
String s2 = "ABZDEFKG";
System.out.println("最长公共子序列长度:" + getLCS(s1, s2));
}
public static int getLCS(String s1, String s2) {
char[] a = s1.toCharArray();
char[] b = s2.toCharArray();
// a.length行,b.length列
int[][] result = new int[a.length + 1][b.length + 1];
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < b.length; j++) {
if (a[i] == b[j]) {
result[i + 1][j + 1] = result[i][j] + 1;
} else {
result[i + 1][j + 1] = Math.max(result[i][j + 1], result[i + 1][j]);
}
}
}
// ----- print table -----
System.out.print(" ");
for (int i = 0; i < b.length; i++) {
System.out.print(" " + b[i]); // 打印第一行
}
System.out.println();
for (int i = 1; i < result.length; i++) {
System.out.print(a[i - 1] + " ");
for (int j = 1; j < result[i].length; j++) {
System.out.print(result[i][j] + " ");
}
System.out.println();
}
System.out.println();
// -----------------------
return result[a.length][b.length];
}
}
注意上面代码中 print table
打印部分仅是为了给大家展示表格帮助理解,实际中并不需要。
执行结果:
A B Z D E F K G
A 1 1 1 1 1 1 1 1
B 1 2 2 2 2 2 2 2
C 1 2 2 2 2 2 2 2
D 1 2 2 3 3 3 3 3
E 1 2 2 3 4 4 4 4
F 1 2 2 3 4 5 5 5
G 1 2 2 3 4 5 5 6
最长公共子序列长度:6