最短公共超序列
难度:
标签:
题目描述
代码结果
运行时间: 324 ms, 内存: 391.9 MB
/*
* 思路: 这个解法与上一个类似,但是我们利用Java的Stream API来处理字符串的拼接部分。
* 同样地,我们先用动态规划求出最短公共超序列的长度表,然后反向构建结果字符串。
*/
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class ShortestCommonSupersequenceStream {
public String shortestCommonSupersequence(String str1, String str2) {
int m = str1.length();
int n = str2.length();
int[][] dp = new int[m + 1][n + 1];
// 初始化 dp 数组
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= n; j++) {
if (i == 0) {
dp[i][j] = j;
} else if (j == 0) {
dp[i][j] = i;
} else if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);
}
}
}
// 使用 Stream 反向构建结果字符串
String result = IntStream.iterate(m + n - 1, i -> i >= 0, i -> i - 1)
.mapToObj(i -> new Object() {
int index = i;
char ch = (index >= m) ? str2.charAt(index - m) : str1.charAt(index);
})
.filter(obj -> {
if (obj.index >= m || obj.index >= n) return true;
if (str1.charAt(obj.index) == str2.charAt(obj.index)) return true;
return dp[m - obj.index - 1][n - obj.index - 1] + 1 == dp[m - obj.index][n - obj.index];
})
.map(obj -> String.valueOf(obj.ch))
.collect(Collectors.joining());
return result;
}
}
解释
方法:
此题解采用动态规划先找出两个字符串的最长公共子序列(LCS),然后构建最短公共超序列(SCS)。首先,使用一个二维数组dp,其中dp[i][j]存储s1的前i个字符和s2的前j个字符的LCS。遍历两个字符串,填充dp数组。接着,根据dp数组的内容,从头到尾构建出SCS。在构建SCS的过程中,如果当前字符属于LCS,则添加这个字符到结果中,同时移动两个字符串的指针;如果不是,则分别添加两个字符串的当前字符,直到处理完所有字符。
时间复杂度:
O(l1 * l2)
空间复杂度:
O(l1 * l2)
代码细节讲解
🦆
在动态规划过程中,dp数组的维度是如何确定的,为什么选择使用二维数组?
▷🦆
题解中提到构建SCS时,如果当前字符不属于LCS,则同时添加两个字符串的当前字符。这种做法是否可能导致结果不是最短的公共超序列?
▷🦆
在计算LCS时,为何选择从后向前遍历字符串进行动态规划填表,而不是从前向后?
▷🦆
在构建最短公共超序列的过程中,如何处理两个字符串中的剩余字符,以确保最终结果符合题目要求?
▷