来源 : 牛客题霸第127题
题目
给定两个字符串str1和str2,输出两个字符串的最长公共子串
题目保证str1和str2的最长公共子串存在且唯一。
示例1
str1 = “1AB2345CD”, str2 = “12345EF”
最长公共子串 “2345”
思路
用一维数组dp 保存str1某个元素在str2中已连续的个数
dp数组的长度比str2的长度大1
我们把str1的每个元素按序在str2中倒序比对,如果相等,则在dp对应的元素位的值设置为前一个元素位的值+1,表示已连续的个数。不相等,则设置为0,
同时需要记录str2中最大长度时的索引和最大长度值
str1 元素中1遍历后的
最大长度索引为0,最大长度为1
dp数组的值
str2 | 1 | 2 | 3 | 4 | 5 | E | F | |
---|---|---|---|---|---|---|---|---|
dp | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
str1 元素中A遍历后的
最大长度索引为0,最大长度为1
dp数组的值
str2 | 1 | 2 | 3 | 4 | 5 | E | F | |
---|---|---|---|---|---|---|---|---|
dp | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
str1 元素中B遍历后的
最大长度索引为0,最大长度为1
dp数组的值
str2 | 1 | 2 | 3 | 4 | 5 | E | F | |
---|---|---|---|---|---|---|---|---|
dp | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
str1 元素中2遍历后的
最大长度索引为1,最大长度为1
dp数组的值
str2 | 1 | 2 | 3 | 4 | 5 | E | F | |
---|---|---|---|---|---|---|---|---|
dp | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
str1 元素中3遍历后的
最大长度索引为2,最大长度为2
dp数组的值
str2 | 1 | 2 | 3 | 4 | 5 | E | F | |
---|---|---|---|---|---|---|---|---|
dp | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 |
str1 元素中4遍历后的
最大长度索引为3,最大长度为3
dp数组的值
str2 | 1 | 2 | 3 | 4 | 5 | E | F | |
---|---|---|---|---|---|---|---|---|
dp | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 |
str1 元素中5遍历后的
最大长度索引为4,最大长度为4
dp数组的值
str2 | 1 | 2 | 3 | 4 | 5 | E | F | |
---|---|---|---|---|---|---|---|---|
dp | 0 | 0 | 0 | 0 | 0 | 4 | 0 | 0 |
str1 元素中C遍历后的
最大长度索引为4,最大长度为4
dp数组的值
str2 | 1 | 2 | 3 | 4 | 5 | E | F | |
---|---|---|---|---|---|---|---|---|
dp | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
str1 元素中D遍历后的
最大长度索引为4,最大长度为4
dp数组的值
str2 | 1 | 2 | 3 | 4 | 5 | E | F | |
---|---|---|---|---|---|---|---|---|
dp | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
最后截取str2 的最大长度索引往前推最大长度的字符串为最长公共子串
示例代码
public static void main(String[] args) {
String str1 ="asgsdfasd"; String str2 ="sdgsdfadsdAS";
System.out.println(calc(str1,str2));
}
public static String calc(String str1, String str2) {
int maxLenth = 0;
//记录最长公共子串的长度
//记录最长公共子串最后一个元素在字符串 str1中的位置
int maxLastIndex = 0;
int[] dp = new int[str2.length() + 1];
for (int i = 0; i < str1.length(); i++) {
// 注意这里是倒序
for (int j = str2.length() - 1; j >= 0; j--) {
//递推公式, 两个字符相等的情况
if (str1.charAt(i) == str2.charAt(j)) {
dp[j + 1] = dp[j] + 1;
// 如果遇到了更长的子串,要更新,记录最长子串的长度,以及最长子串最后一个元素的位置
if (dp[j + 1] > maxLenth) {
maxLenth = dp[j + 1];
maxLastIndex = i;
}
} else {
// 两个字符不相等则当前位置设为0
// 每次str1新元素开始在str2倒序比对时,dp数组的值是上个元素比较后的最新值
dp[j + 1] = 0;
}
}
}
// 最字符串进行截取, substring(a,b) 中 a 和 b 分别表示截取的开始和结束位置
return str1.substring(maxLastIndex - maxLenth + 1, maxLastIndex + 1);
}
运行结果
gsdfa