给出两个字符串,写一个函数找到最长公共子串,并返回其长度。
注意事项:
子串的字符应该连续的出现在原字符串中,这与子序列有所不同。
格式:
输入行输入两个字符串 A 和 B,最后输出最长公共子串的长度。
样例输入
A = “ABCD”
B = “CBCE”
样例输出
2
动态规划算法即可。
用“ABDABC”和“ABEABC”做解题思路。直接先上动态规划表。
" | A | B | D | A | B | C | |
" | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 1 | 0 | 0 | 1 | 0 | 0 |
B | 0 | 0 | 2 | 0 | 0 | 2 | 0 |
E | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 1 | 0 | 0 | 1 | 0 | 0 |
B | 0 | 0 | 2 | 0 | 0 | 2 | 0 |
C | 0 | 0 | 0 | 0 | 0 | 0 | 3 |
横坐标为i(代表行),纵坐标为j(代表列)上面表格中可以看出
i=0,则由与是空字符串,则该行对应的每一列都是0
从i=1开始
1、如果第j列对应的字符与第i行对应的字符相等,则单元格(i,j)=(i-1,j-1)+1。为什么?因为在当前第i行与第j列相等的情况下,最长的公共字符串就是前面i-1行,j-1列最长的公共字符串加上当前的这一个公共字符。
2、如果第j列对应的字符与第i行对应的字符不等,则单元格(i,j)=0
从上表格中可以看出,公共字符串有多个,那么最长的公共字符串的最后一个字符对应的(i,j)值是可以找到的,由此往前(i-1,j-1)做回溯,就可以找到公共字符串。
代码如下:
package suanfa;
import java.util.HashMap;
import java.util.Map;
public class MaxLengthChars {
public static void main(String[] args) {
String str1 = "ABCERQQQQQTVERTYUIQRRRRRRRMNBTRASDG";
String str2 = "ABCERQQQQQPVERTYUIQRRRRRRRADCDFEDC";
Map<String,Object> map = compute(str1, str2);
System.out.println("最长公共字符串长度为:"+map.get("maxLength"));
System.out.println(getCommonChars((int[][])map.get("map"), str1, (int)map.get("I"),(int)map.get("J")));
}
/**
*
* @param map
* @param str1
* @param i
* @param j
* @return
*/
public static String getCommonChars(int[][] map, String str1, int i, int j) {
String res = "";
while (map[i][j] != 1) {
res = str1.substring(i - 1, i) + res;
i--;
j--;
}
return str1.substring(i - 1, i) + res;
}
/**
* 计算最长公共字符串
*
* @param str1
* @param str2
* @return
*/
public static Map<String,Object> compute(String str1, String str2) {
Map<String,Object> rmap = new HashMap<String,Object>();
str1 = "\0" + str1;
str2 = "\0" + str2;
char[] arr1 = str1.toCharArray();
char[] arr2 = str2.toCharArray();
int maxLength = 0;
int[][] map = new int[arr1.length][arr2.length];
for (int i = 0; i < arr1.length; i++) {
map[i][0] = 0;
}
for (int i = 0; i < arr2.length; i++) {
map[0][i] = 0;
}
for (int i = 1; i < arr1.length; i++) {
for (int j = 1; j < arr2.length; j++) {
if (arr1[i] == arr2[j]) {
if (arr1[i - 1] == arr2[j - 1]) {
map[i][j] = map[i - 1][j - 1] + 1;
if(maxLength < map[i][j]){
maxLength = map[i][j];
rmap.put("maxLength", map[i][j]);
rmap.put("I", i);
rmap.put("J", j);
}
} else {
map[i][j] = 1;
}
} else {
map[i][j] = 0;
}
}
}
rmap.put("map", map);
return rmap;
}
}
运行结果:
最长公共字符串长度为:15
VERTYUIQRRRRRRR