验证回文串 III
难度:
标签:
题目描述
代码结果
运行时间: 116 ms, 内存: 17.9 MB
// 思路:
// 这道题的目标是验证一个字符串能否通过删除最多 k 个字符变成一个回文串。
// 我们使用动态规划来解决这个问题。
// 定义 dp[i][j] 表示字符串 s 在子串 i 到 j 范围内变成回文所需删除的最少字符数。
// 如果 s.charAt(i) == s.charAt(j),那么 dp[i][j] = dp[i+1][j-1]。
// 否则,dp[i][j] = min(dp[i+1][j], dp[i][j-1]) + 1。
// 我们需要判断 dp[0][n-1] 是否 <= k,其中 n 是字符串 s 的长度。
import java.util.stream.IntStream;
public class Solution {
public boolean isValidPalindrome(String s, int k) {
int n = s.length();
int[][] dp = new int[n][n];
IntStream.range(1, n).forEach(len ->
IntStream.range(0, n - len).forEach(i -> {
int j = i + len;
if (s.charAt(i) == s.charAt(j)) {
dp[i][j] = dp[i + 1][j - 1];
} else {
dp[i][j] = Math.min(dp[i + 1][j], dp[i][j - 1]) + 1;
}
})
);
return dp[0][n - 1] <= k;
}
}
解释
方法:
这道题目的解法使用了动态规划的思路来处理问题。首先定义了一个二维数组dp,其中dp[i][j]表示为了使子字符串s[i:j+1]成为回文串需要删除的最小字符数。算法从字符串的后端开始遍历,通过比较字符是否相同来递推填充dp数组。如果字符相同,dp[i][j]则由dp[i+1][j-1]决定,并增加2表示两端字符相同。如果字符不同,则考虑删除左端或右端字符的情况,取两者中较大的值。过程中,如果任何dp[i][j]的值大于等于n-k(k为允许删除的最大字符数),则返回True,表示可以通过删除不超过k个字符使得s成为回文串。如果遍历完所有字符对都没有返回True,则最后返回False。
时间复杂度:
O(n^2)
空间复杂度:
O(n^2)
代码细节讲解
🦆
为什么在初始化动态规划数组`dp`时,每个`dp[i][i]`的值是设定为1而不是0?
▷🦆
在递推关系中,当`s[left]`不等于`s[right]`时,为什么选择取`dp[left + 1][right]`和`dp[left][right - 1]`中的最大值而不是最小值?
▷🦆
题解中提到,如果`dp[left][right]`的值大于等于`n - k`就返回True,请问这是如何确保删除的字符数量不超过k的?
▷🦆
在题解算法中如何处理字符串s中可能存在的特殊字符或者空字符串输入?
▷