Solution1:我的答案1
直接模仿131那道题的DFS解法,找其中size最小的。果不其然,因为超时只能部分AC。代码如下,仅供记录:
class Solution {
public:
int minCut(string s) {
vector<string> temp;
vector<string> res;
PalinDFS(s, 0, temp, res);
return res.size() - 1;
}
void PalinDFS (string str, int start, vector<string> &temp, vector<string> &res) {
if (start == str.size()) {
if (res.size() == 0 || res.size() > temp.size())
res = temp;
return;
}
for (int i = start; i < str.size(); i++) {
if (isPalin(str, start, i)) {
temp.push_back(str.substr(start, i - start + 1));
PalinDFS(str, i + 1, temp, res);
temp.pop_back();
}
}
}
bool isPalin(string str, int begin, int end) { //[begin, end]是[闭,闭]区间
int left = begin, right = end;
while (left < right) {
if (str[left] != str[right])
return false;
else {
left++;right--;
}
}
return true;
}
};
Solution2:
参考网址:https://blog.csdn.net/jingsuwen1/article/details/51934277
解题思路:动态规划问题。
dp[i]表示子串[0, i]的最小回文切割,则最优解在dp[s.length-1]中。[0, i]的子串中包括了i+1个字符。
分几种情况:
1.初始化:当字串s[0:i] (包括i位置的字符)是回文串时,dp[i] = 0(表示不需要分割);否则,dp[i] = i(表示至多分割i次);
2.对于任意大于1的i,如果s[j:i]( 1 =< j <= i,即遍历i之前的每个子串)是回文时,dp[i] = min(dp[i], dp[j-1]+1);
(注:j不用取0是因为若j == 0,则又表示判断(0,i))。
相对容易理解的动态规划方法。
class Solution {
public:
int minCut(string s) {
if (s.size() == 0) return 0;
//dp[i]存放以i位置字符结尾的字符串的最小切割数,即所求为dp[s.size() - 1]
int dp[s.size()];
dp[0] = 0;//单个字符,无需切割
for(int i = 0; i < s.size(); i++) {
//dp[i]赋初值
dp[i] = isPalin(s, 0, i)? 0 : i;
//1 =< j <= i子串回文判定
for (int j = i; j >= 1; j--) {
if (isPalin(s, j, i))
dp[i] = min(dp[i], dp[j-1] + 1);
}
}
return dp[s.size() - 1];
}
bool isPalin(string &str, int begin, int end) {
while (begin < end) {
if (str[begin] != str[end])
return false;
else
begin++;end--;
}
return true;
}
};
//20180718日更新,DP算法真厉害啊!
class Solution {
public:
int minCut(string s) {
if (s.size() <= 1) return 0;
int dp[s.size()];
for (int i = 0; i < s.size(); i++) {
dp[i] = isPalin(s, 0, i) == 1? 0:i;
for (int j = 1; j <= i; j++) {
if (isPalin(s, j, i)) {
dp[i] = min(dp[i], dp[j-1] + 1);
}
}
}
return dp[s.size() - 1];
}
int isPalin(string& str, int begin, int end) {
while (begin < end) {
if (str[begin] != str[end])
return 0;
else {
begin++;
end--;
}
}
return 1;
}
};
Solution3:更优化的动态规划方法
参考网址:
http://www.cnblogs.com/grandyang/p/4271456.html
这道题是让找到把原字符串拆分成回文串的最小切割数,需要用动态规划Dynamic Programming来做,使用DP的核心是在于找出递推公式,之前有道地牢游戏Dungeon Game的题也是需要用DP来做,而那道题是二维DP来解,这道题由于只是拆分一个字符串,需要一个一维的递推公式,我们还是从后往前推,递推公式为:dp[i] = min(dp[i], 1+dp[j+1] ) i<=j
//在20180719搞懂了。。。
class Solution {
public:
int minCut(string s) {
int len = s.size();
bool P[len][len];
int dp[len + 1];
for (int i = 0; i <= len; ++i) {
//之所以要初始化dp[len] = -1
//是为了当 j + 1 == len时计算用
dp[i] = len - i - 1;
}
for (int i = 0; i < len; ++i) {
for (int j = 0; j < len; ++j) {
if (i == j)
P[i][j] = true;
else
P[i][j] = false;
}
}
for (int i = len - 1; i >= 0; --i) {
for (int j = i; j < len; ++j) {
//更新p[i][j]时要用到i + 1和j - 1,故i要从大到小遍历,j要从小到大遍历
if (s[i] == s[j] && (j - i <= 1 || P[i + 1][j - 1])) {
P[i][j] = true;
//dp[i]表示从s[i, s.size()-1]部分(闭闭区间)字符串的最小分割数
dp[i] = min(dp[i], dp[j + 1] + 1);
}
}
}
return dp[0];
}
};