描述
给定两个字符串str1和str2,输出两个字符串的最长公共子串
题目保证str1和str2的最长公共子串存在且唯一。
数据范围: 1≤∣str1∣,∣str2∣≤5000
要求: 空间复杂度O(n2),时间复杂度O(n2)
示例1
输入:
"1AB2345CD","12345EF"
返回值:
"2345"
dp背包问题
s1 = "1AB2345CD"
s2 = "12345EF"
当 s1 的 xPos 位置 = s2 的 yPos 的字符时,它的最大长度等于 dp[yPos-1][xPos-1] + 1,那么 dp 公式就出来了
public String LCS (String str1, String str2) {
// write code here
if (str1 == null || str2 == null || str1.isEmpty() || str2.isEmpty()) {
return "";
}
int length1 = str1.length();
int length2 = str2.length();
int[][] dpMap = new int[length2][length1];
int xPos;
int yPos;
int maxXPos = 0;
int maxLength = 0;
// 初始化 dpMap
for (xPos = 0; xPos < length1; xPos++) {
char c = str2.charAt(0);
if (c == str1.charAt(xPos)) {
dpMap[0][xPos] = 1;
}
}
for (yPos = 1; yPos < length2; yPos++) {
char c = str1.charAt(0);
if (c == str2.charAt(yPos)) {
dpMap[yPos][0] = 1;
}
}
for (yPos = 1; yPos < length2; yPos++) {
for (xPos = 1; xPos < length1; xPos++) {
if (str1.charAt(xPos) == str2.charAt(yPos)) {
int temp = dpMap[yPos-1][xPos-1] + 1;
dpMap[yPos][xPos] = temp;
if (temp > maxLength) {
maxXPos = xPos;
maxLength = temp;
}
}
}
}
return str1.substring(maxXPos-maxLength+1, maxXPos+1);
}
二维背包时间复杂度 O(n^2),空间复杂度 O(n^2)。但因为本体的特殊性,子串是连续的字符串,所以可以用反向的一维数组代替。
即 dp[xPos] = dp[xPos-1] + 1
此处 dp[xPos] 是这个循环的当前位置,而 dp[xPos-1] 是上个循环的当前位置
for (yPos = 1; yPos < length2; yPos++) {
for (xPos = length1-1; xPos >= 0; xPos--) {
if (str1.charAt(xPos) == str2.charAt(yPos)) {
int temp = dpMap[xPos] + 1;
dpMap[xPos+1] = temp;
if (temp > maxLength) {
maxXPos = xPos;
maxLength = temp;
}
} else {
dpMap[xPos+1] = 0;
}
}
}