给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回符合要求的最少分割次数。
示例:
输入: "aab"
输出: 1
解释: 进行一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/palindrome-partitioning-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
1.递归+回溯
记录每一次分割所需要的次数,求最小值
代码如下:
class Solution {
public:
int minNum=INT_MAX;
int minCut(string s) {
vector<string> str;
dfs(s,0,str);
return minNum;
}
void dfs(string s,int start,vector<string> &str)
{
if(start==s.size())
{
minNum=minNum>(str.size()-1)?str.size()-1:minNum;
return;
}
for(int i=start;i<s.size();i++)
{
int left=start,right=i;//如果left--right是回文则加入
int flag=1;
while(left<right)
{
if(s[left]==s[right])
{
left++;
right--;
}
else
{
flag=0;
break;
}
}
if(flag==1)
{
str.push_back(s.substr(start,i-start+1));
dfs(s,i+1,str);
str.pop_back();
}
}
}
};
结果超时
2.动态规划+中心扩展法
设dp[i]表示以i结尾的最小分割次数,遍历字符串中每一个元素,对于当前元素i使用中心扩展法,假设最后两边分别扩展到left,right,即(left,right)之间是回文字符串,则dp[right]=min(dp[right],dp[left-1]+1)
代码如下:
class Solution {
public:
int minCut(string s) {
int n = s.size();
vector<int> dp(n);
for (int i = 0; i < n; ++i) dp[i] = i;
for (int i = 0; i < n; ++i) {
centerExpand(s, dp, i, i);
centerExpand(s, dp, i, i + 1);
}
return dp[n - 1];
}
void centerExpand(string& s, vector<int>& dp, int l, int r) {
while (l >= 0 && r < s.size() && s[l] == s[r]) {
if (l == 0)
dp[r] = 0;
else
dp[r] = min(dp[r], dp[l - 1] + 1);
l--;
r++;
}
}
};