解题思路:
这个简单的方法就是,用回溯,一个个的遍历。每一次从下一个遍历之前,都需要判断当前子串是不是回文串,这里的回文串检查可以用动态规划储存起来,加快速度:
dp[i][j]是不是回文串,判断s[i] == s[j] && ( j - i < 3 || dp[i+1][j-1])
class Solution {
public:
bool IsHUIWEN(string s)
{
int l = 0;
int r = s.size()-1;
while(l<r)
{
if(s[l++]!=s[r--])
return false;
}
return true;
}
void backthrough(string s,int cur,vector<string> sub,
vector<vector<string>> &res,
vector<vector<int>> &dp)
{
if(cur>=s.size())
{
res.push_back(sub);
return ;
}
for(int i = cur;i<s.size();i++)
{
//if(IsHUIWEN(s.substr(cur,i-cur+1)))
if(s[cur]==s[i] && (i-cur < 3 || dp[cur+1][i-1]))
{
dp[cur][i]=1;
sub.push_back(s.substr(cur,i-cur+1));
backthrough(s,i+1,sub,res,dp);
sub.pop_back();
}
}
}
vector<vector<string>> partition(string s) {
vector<vector<string>> res ;
vector<vector<int>> dp(s.size(),vector<int>(s.size()));
for(int i = 0;i<s.size();i++)
{
dp[i][i]=1;
}
vector<string> temp;
backthrough(s,0,temp,res,dp);
return res;
}
};
下面统计最小的分割回文串
如果沿着上一题的做法,就是将每一次分隔到最后将分割的次数记录下来,比较大小;但这样做还是重复记录了很多次,会超时,从而就再需要辅助空间来降低复杂度;
我们可以从前往后遍历,即自底向上,用dp[i] 记录前i个字符是回文串并且分割次数是最小的,如果j是从中的一次分割,那么dp[j]表示前j个字符分割回文最小的次数,从0开始遍历,如果i到j是回文的,
那么dp[j]=min(dp[j],dp[i]+1);意思就是说只要从i分割一刀,那么只要前i个字符串回文分割次数最小dp[i]再加上1,就表示从i分割,此时dp[j]最小。
class Solution {
public:
bool IsHUIWEN(string s)
{
int l = 0;
int r = s.size()-1;
while(l<r)
{
if(s[l++]!=s[r--])
return false;
}
return true;
}
void backthrough(string s,int cur,int num,int &res,vector<vector<int>> &dp)
{
if(cur>=s.size())
{
res=min(res,num);
return ;
}
for(int i = cur;i<s.size();i++)
{
//if(IsHUIWEN(s.substr(cur,i-cur+1)))
if(s[cur]==s[i] && (i-cur < 3 || dp[cur+1][i-1]))
{
dp[cur][i]=1;
backthrough(s,i+1,num+1,res,dp);
}
}
}
void cut(string s ,vector<vector<int>> &dp,vector<int> &f)
{
int n = s.size();
for(int i = 1; i <= n; i++){
//表示刚开始每一处都分割一次
f[i] = i;
for(int j = 0; j < i; j++){
if(s[j]==s[i-1] && (i-1-j < 3 || dp[j+1][i-2])){
dp[j][i-1]=1;
f[i] = min(f[j] + 1, f[i]);
}
}
}
}
int minCut(string s) {
int res = 999;
vector<vector<int>> dp(s.size(),vector<int>(s.size()));
for(int i = 0;i<s.size();i++)
{
dp[i][i]=1;
}
vector<int> f(s.size()+1);
f[0]=-1;
//f[0]是-1很重要,表示从0开始到j就是回文的,那么f[0]+1 = 0表示不需要进行分割。
cut(s,dp,f);
return f[s.size()];;
}
};