【LeetCode-132】分割回文串 II
问题
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。
返回符合要求的 最少分割次数 。
示例
输入: s = "aab"
输出: 1
解释: 只需一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。
解答
class Solution {
public:
int minCut(string s) {
int n = s.size();
bool dp[n][n]; memset(dp, 1, sizeof(dp));
int f[n]; // f[i]表示以i结尾的字符串最少分割次数
for (int i = n - 1; i >= 0; i--)
for (int j = i + 1; j < n; j++)
dp[i][j] = (s[i] == s[j]) && dp[i + 1][j - 1];
for (int j = 0; j < n; j++) {
if (dp[0][j]) f[j] = 0; // 是内层循环中i=0时的特例,边界
else {
f[j] = f[j - 1] + 1; // 以s[j]单独分隔作为初始化
for (int i = 1; i < j; i++) // 遍历[i, j]能够形成回文串的分割次数,取其中最小
if (dp[i][j]) f[j] = min(f[j], f[i - 1] + 1);
}
}
return f[n - 1];
}
};
重点思路
这道题还是有点麻烦。使用动态规划预处理回文串在之前的文章已经讲过具体操作。本题的重难点在于如何使用动态规划,使用上一状态的最小分割次数推导下一状态的最小分割次数。
首先需要有一个大致的思路。首先分析一般情况,我们要遍历上一状态中所有元素,设当前遍历到角标i
,若[i, j]
这一段字符串满足回文要求,则可以以i
元素前为分割点,此时切割次数需要f[j] = f[i - 1] + 1
,遍历所有元素取最小值,此时我们可以得到状态转移方程为if (满足要求) f[j] = min(f[j], f[i - 1] + 1)
。然后分析边界条件,由状态方程可以得到,i = 0
时会越界。当i = 0
时,此时直接判断[0, j]
这一段字符串是否为回文串。分析状态方程可以得知,每个f[i]
都需要初始化,这里的做法是每个单独初始化。