对字母串可执行的最大删除数
难度:
标签:
题目描述
代码结果
运行时间: 3642 ms, 内存: 317.5 MB
/*
* 题目思路:
* - 这里我们使用 Java Stream 来简化代码。
* - 使用 Stream 的 map 和 reduce 操作来替代常规的循环操作。
* - 思路和前面的解法类似,我们仍然是计算 dp 数组。
*/
import java.util.stream.IntStream;
public int deleteString(String s) {
int n = s.length();
int[] dp = new int[n + 1];
IntStream.range(0, n).forEach(i -> dp[i] = 1);
IntStream.range(0, n).map(i -> n - 1 - i).forEach(i ->
IntStream.range(1, (n - i) / 2 + 1).forEach(k -> {
if (s.substring(i, i + k).equals(s.substring(i + k, i + 2 * k))) {
dp[i] = Math.max(dp[i], 1 + dp[i + k]);
}
})
);
return dp[0];
}
解释
方法:
此题解采用动态规划的方法解决问题。定义一个数组 f,其中 f[i] 表示从字符串的第 i 个字符开始到结束所有可能的删除操作的最大数目。具体过程中,先计算字符串任意两个后缀的最长公共前缀(LCP),存储在二维数组 lcp 中。然后使用这个 lcp 数组来快速判断任意两个相等长度的子串是否相等。对于每个位置 i,检查所有可能的 j(长度为从 1 到 (n-i)/2 的子串),如果 s[i:i+j] 等于 s[i+j:i+2j],则尝试更新 f[i] 为 f[i+j]+1 的最大值。最终,f[0] 即为整个字符串 s 的最大删除次数。
时间复杂度:
O(n^2)
空间复杂度:
O(n^2)
代码细节讲解
🦆
在动态规划解法中,你是如何确定f数组的初始值以及更新规则的?
▷🦆
为什么在构建最长公共前缀(LCP)数组时选择从后向前计算,而不是从前向后?
▷🦆
在计算最长公共前缀(LCP)时,如何处理边界条件,特别是当i或j接近字符串末尾时?
▷🦆
在对f数组进行更新时,你是如何利用lcp数组来判断两个子串是否相等的?具体的判断条件是什么?
▷