題意:找出一個字符串中的所有切割使得切割後的子串都是迴文字符串。
首先想到一個簡單的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];
}
};