给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回符合要求的最少分割次数。
示例:
输入: "aab"
输出: 1
解释: 进行一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。
请先翻阅 LeetCode 分割回文子串
此题就是在上一题将所有分割方法修改为最少的分割次数。
方法一:回溯法。继续使用上一题的代码,只是在dfs函数中添加一个变量记录分割的次数,并寻找到分割次数最少的分割方法。(但是超时了。。。)
class Solution {
public:
int minResult = INT_MAX;
int minCut(string s) {
if (s == "") {
return 0;
}
dfs(s, 0, 0);//开始搜索
return minResult;
}
//从beginIndex开始,寻找回文子串
void dfs(string &str, int beginIndex, int steps) {
int strSize = str.size();
if (beginIndex == strSize) {//如果截取到了尾端,说明寻找到了一个解
minResult = min(minResult, steps - 1);
return;
}
//对截取长度进行穷举
int endIndex = strSize - 1;
while (endIndex >= beginIndex) {
if (isPalindrome(str, beginIndex, endIndex)) {//如果当前截取的[beginIndex, endIndex]段是回文串
dfs(str, endIndex + 1, steps + 1);//以endIndex + 1下标为起始,继续寻找
}
--endIndex;
}
}
//判断在str串中截取[beginIndex, endIndex]段是否是回文串
bool isPalindrome(string &str, int beginIndex, int endIndex) {
while (beginIndex < endIndex) {
if (str[beginIndex++] != str[endIndex--]) {
return false;
}
}
return true;
}
};
方法二:动态规划。
class Solution {
public:
int minCut(string s) {
if (s == "") {
return 0;
}
int strSize = s.size();
vector<vector<bool>> judge(strSize, vector<bool>(strSize, false));//judge[j][i]用于记录s串[i,j]是否是回文
vector<int> dp(strSize, INT_MAX);//dp[i]用于记录s串中[0, i]需要分割的次数
for (int i = 0; i < strSize; ++i) {
for (int j = 0; j <= i; ++j) {//从[j, i]
if (s[i] == s[j] && (i - j <= 1 || judge[j + 1][i - 1])) {
judge[j][i] = true;
if (j != 0) {//如果j == 0,说明[0, i]都是回文
//dp[j - 1] + 1 表示的分割[0, j - 1] + [j, i]需要分割的次数一个解
dp[i] = min(dp[i], dp[j - 1] + 1);
}
else {
dp[i] = 0;
}
}
}
}
return dp[strSize - 1];
}
};