题意:找出一个字符串中的所有切割使得切割后的子串都是回文字符串。
首先想到一个简单的DP判断从i到j是否能组成回文。
设dp[i][j] = 1代表a[i]到a[j]组成的子串是回文,反之则不是。
转移方程:若dp[i+1][j-1] = 1且a[i] = a[j]则dp[i][j] = 1。
然后寻找所有切割可以使用DFS,深搜每个可能的分割。
代码如下:
class Solution {
public:
int DFS(int index, vector<vector<bool> >& isPa, int sLen, vector<string>& tmp, string& s) {
//表示寻找从index开始的回文字符子串
if(index == sLen) {
ans.push_back(tmp);
return 1;
}
string tmpStr;
for(int i = index;i < sLen;i++) {
tmpStr += s[i];
if(isPa[index][i]) {
tmp.push_back(tmpStr);
DFS(i+1, isPa, sLen, tmp, s);
tmp.pop_back();
}
}
return 0;
}
vector<vector<string>> partition(string s) {
int sLen = s.size();
if(sLen == 0)
return ans;
vector<vector<bool> > isPa(sLen, vector<bool>(sLen, 0));
for(int i = sLen-1;i >= 0;i--) {
isPa[i][i] = 1;
for(int j = i+1;j < sLen;j++) {
if((isPa[i+1][j-1] || i == j-1) && s[i] == s[j]) {
isPa[i][j] = 1;
}
}
}
vector<string> tmp;
DFS(0, isPa, sLen, tmp, s);
return ans;
}
private:
vector<vector<string> > ans;
};
对于第二个变式,需要加入另一个dp,因为一种切割必定有一个回文在它的最边缘。
设minCutNum[i]为从a[i]到a[N-1]组成的字符串的最小切割。
则转移方程为:若isPa[i][j],则minCutNum[i] = min(minCutNum[i], minCutNum[j+1]+1),其中i<=j<=N-1.
代码如下:
class Solution {
public:
int minCut(string s) {
int sLen = s.size();
if(sLen == 0) return 0;
vector<bool> isPa(sLen, 0);
vector<int> minCutNum(sLen+1, INT_MAX-1);
minCutNum[sLen] = -1;
//minCutNum[i]表示从0到i的串的最小切割
for(int i = sLen-1;i >= 0;i--) {
for(int j = i;j < sLen;j++) {
if((i == j || i == j-1 || isPa[j-1]) && s[i] == s[j]) {
isPa[j] = 1;
minCutNum[i] = min(minCutNum[j+1]+1, minCutNum[i]);
}
}
}
return minCutNum[0];
}
};