给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。
返回符合要求的 最少分割次数 。示例 1: 输入:s = “aab” 输出:1 解释:只需一次分割就可将 s 分割成 [“aa”,“b”] 这样两个回文子串。
这题是hard,可以和131.分割回文串I,647.回文子串,5.最长回文子串三道题结合起来看,也相当于他们的升级版
对于下标从0~i
的字符串,如果不是回文的话,那么假设中间1个分割点为下标j
dp[i]是0~i下标的字符串的分割次数,那么
0 ~ i
是回文时,显然dp[i] = 0
;即不用分割0 ~ i
不是回文时,如果分割点j使得 j ~ i
是回文,那么dp[i] = dp[j] + 1;
当然对于不同j,我们要取最小值,所以dp[i] = min(dp[i], dp[j] + 1);
注意:j一定要能取到i - 1,此时j + 1就是i,那么此时j + 1 = i, 而i ~ i 一定是回文
否则,像我一开始想的是,j - 1 < i,这样如果j + 1 ~ i是两个字符的话,那么这两个字符可能是回文,也可能不是回文。递推公式就更麻烦了。
下面我用O(N)的双指针法写函数来判断子串是否回文,这样需要反反复复调用函数,使得耗时很大。
class Solution {
private:
//判断是否回文串的函数
bool isHui(const string& s, int start, int end){
for(int i = start, j = end; i < j; i++, j--){
if(s[i] != s[j]) return false;
}
return true;
}
public:
int minCut(string s) {
vector<int>dp(s.size(), INT_MAX);
dp[0] = 0;
for(int i = 1; i < s.size(); i++){
//递推公式是适用于0~i不是回文的,所以先处理0~i为回文情况
if(isHui(s, 0, i)){
dp[i] = 0;
continue;//注意要跳过当前i了
}
for(int j = 0; j < i;j++){ // j 要取到i - 1,这样才能使得j + 1= i ~ i一定是回文,因为递推公式,比如dp[2] = min(dp[2], dp[1] + 1)
if(isHui(s, j+1, i)){
dp[i] = min(dp[i], dp[j] + 1);
}
}
}
return dp[s.size() - 1];
}
};
== 在for循环里反复调用函数,使得耗时太大。不过内存消耗小。==
用dp数组,记录子串是否为回文串,这样避免函数的调用。
dp数组记录是否为回文的方法就是647题回文子串
这里使用精简过的,原理就是:
如果当前s[i] == s[j]
,那么如果i和j相差不大于1,也就是要么i和j指向同一个字符,要么i到j就是两个字符
,比如aa,那此时肯定是回文。
或者就是递推关系,即i + 1到 j - 1也是回文
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])) {
isPalindromic[i][j] = true;
}
}
}
class Solution {
public:
int minCut(string s) {
vector<vector<bool>>isHui(s.size(), vector<bool>(s.size(), false));
//dp[i][j]中,i从后往前遍历,j从前往后遍历
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 || isHui[i + 1][j - 1] == true)){
isHui[i][j] = true;
}
}
}
vector<int>dp(s.size(), INT_MAX);
dp[0] = 0;
for(int i = 1; i < s.size(); i++){
if(isHui[0][i]){ //用的dp数组查询当前子串是否为回文
dp[i] = 0;
continue;
}
for(int j = 0; j < i;j++){
if(isHui[j + 1][i]){
dp[i] = min(dp[i], dp[j] + 1);
}
}
}
return dp[s.size() - 1];
}
};