给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。
返回符合要求的 最少分割次数 。
示例 1:
输入:s = “aab”
输出:1
解释:只需一次分割就可将 s 分割成 [“aa”,“b”] 这样两个回文子串。
示例 2:
输入:s = “a”
输出:0
示例 3:
输入:s = “ab”
输出:1
分析:
本题利用的最长上升子序列的dp递推公式,这里不过变成了求最小次数,把前面每个子字符串的最小分割次数记录到dp数组中,比如aab这种情况,dp[1] (对应a),dp[2](对应aa),都是0,到了dp[3] (对应aab)情况时,自己默认最多划分2次,然后参考了aa只需要划分0次,多的自己再多划分1次,这样总共1次就可以了,所以递推式子为 dp[i] = min(dp[i], dp[j] + 1)
为了方便判断条件的直接运用,可以先构造描述字符串s中任意两个子字符串(s[i]到s[j])是否为回文的的二维数组isPalindromic,构造的顺序如下图所示
注释代码如下:
class Solution {
public:
int minCut(string s) {
// 先构造一个记录[i,j]子字符串是否为回文的数组
vector<vector<bool>> isPalindromic(s.size(), vector<bool>(s.size(), false));
for(int i = s.size() - 1; i >= 0; i--){
for(int j = i; j < s.size(); j++){
if(s[i] == s[j] && (j - i <= 1 || isPalindromic[i + 1][j - 1] == true)){
isPalindromic[i][j] = true;
}
}
}
// 初始化dp数组
vector<int> dp(s.size() + 1, 0);
for(int i = 0; i < s.size(); i++) dp[i] = i;
//类比最长上升子序列和套娃思想,每个新加入一个元素的字符串去遍历之前的
for(int i = 1; i < s.size(); i++){
// 只有一直是aaaaaa...这种才能成立if中的条件,if是理想状态
if(isPalindromic[0][i] == true){
dp[i] = 0;
continue;
}
// 对应isPalindromic竖着找第i列的情况,过一遍前面[0,j]的子串需要多少次划分
for(int j = 0; j < i; j++){
if(isPalindromic[j + 1][i] == true){
dp[i] = min(dp[i], dp[j] + 1);
}
}
}
return dp[s.size() - 1];
}
};