132. 分割回文串 II
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回符合要求的最少分割次数。
示例:
输入: "aab"
输出: 1
解释: 进行一次分割就可将 s 分割成 [“aa”,“b”] 这样两个回文子串。
动态规划(中心拓展)预处理+dfs求解(超时)
先动态规划或中心拓展法,得到每两个的位置之间是否为回文字符串;
然后尝试从每个位置切,得到答案——超时;
class Solution {
public:
int minCut(string s) {
//以i为终点的回文子串长度是多少
n=s.size();
dp.resize(n,vector<bool>(n,0));
for(int i=0;i<n;i++)
{
fromcenter(s,i,i);
fromcenter(s,i,i+1);
}
mincnt=INT_MAX;
dfs(0,0);
return mincnt;
}
private:
vector<vector<bool>> dp;
int mincnt;
int n;
void fromcenter(string s,int a,int b)
{
while(a>=0&&b<n&&s[a]==s[b]){
dp[a][b]=1;
a--;b++;
}
return;
}
void dfs(int i,int cnt){
if(i==n) {
mincnt=min(cnt-1,mincnt);
return;
}
for(int t=i;t<n;t++){
if(dp[i][t])
dfs(t+1,cnt+1);
}
return;
}
};
动态规划预处理(中心拓展)+动态规划求解
得到每两个位置是否为回文字符串;
进行动态规划:
res[i]为前i个字符需要切的刀数;
res[i+1]最大为res[i]+1;
遍历0~i,若有dp[j+1][i] 则res[j]+1与res[i]比较,取小值即可;
时间复杂度O(N*N);
class Solution {
public:
int minCut(string s) {
n=s.size();
dp.resize(n,vector<bool>(n,0));
for(int i=0;i<n;i++){
fromcenter(s,i,i);
fromcenter(s,i,i+1);
}
res.resize(n,0);
for(int i=1;i<n;i++)
{
if(dp[0][i]) res[i]=0; //不用分割
else{ //要分割
res[i]=res[i-1]+1;//分割最大次数
for(int j=0;j<i-1;j++)
if(dp[j+1][i])res[i]=min(res[j]+1,res[i]);
//j后面一个到i j之前的刀数+1刀
}
}
return res[n-1];
}
private:
vector<vector<bool>> dp;
vector<int> res;
int n;
void fromcenter(string s,int a,int b){
while(a>=0&&b<n&&s[a]==s[b])
dp[a--][b++]=1;
}
};