132. 分割回文串 II
题目描述
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。返回符合要求的最少分割次数。
示例:
输入: "aab"
输出: 1
解释: 进行一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。
方法1
暴力动态规划,LeetCode耗时40ms,内存消耗9.3MB。
class Solution {
public:
int minCut(string s)
{
int n = s.length();
if(n == 0 || n == 1)
return 0;
vector<int> dp(n);
for(int i=0;i<n;i++)
dp[i] = i;
//这里使用了两个额外的结构来保存信息,其中一个是主要的,
//一个是辅助的
vector<vector<bool>> isPalindrome(n,vector<bool>(n,false));
for(int i = 0;i < n;i++)
{
for(int j = 0;j <= i;j++)
{
if(s[j] == s[i] && (i-j<=2 || isPalindrome[j+1][i-1]))
{
isPalindrome[j][i] = true;
if(j == 0)
dp[i]=0;
else
dp[i] = min(dp[i],1+dp[j-1]);
}
}
}
return dp[n-1];
}
};
方法2
中心扩展法更新dp的值
class Solution {
public:
int minCut(string s) {
int n = s.size();
//dp[i]含义为s[0,i-1]的最小分割次数
//由于这里为了递推的需要,需要使用长度为0时的最小分割次数
//所以,这里的动态规划数组的下标含义为长度
vector<int> dp(n+1, 0);
for(int i = 0; i <= n; i++)
//这里根据递推公式合理的将dp[0]初始化为-1
dp[i] = i-1;
//每一次对当前位置i的中心扩展,只会更新这个扩展的右边界处的dp值,不影响i的左侧已经确定的dp值,
//i处的dp的最终值,在i处如果单独奇数扩展分割后自己构成右边界同i处已有
//的dp值比较后确定。起始时,可以看成i=0的左边处的情况为dp[0]=-1已经确定了
for(int i = 0; i < n; i++)//i为元素下标
{ //j为相对于i的偏移量
for(int j = 0; i-j >= 0 && i+j < n && s[i-j]==s[i+j] ; j++) //奇数 length palindrome
dp[i+j+1] = min(dp[i+j+1],1+dp[i-j]);
for(int j = 0; i-j >= 0 && i+1+j < n && s[i-j] == s[i+1+j]; j++) //偶数 length palindrome
dp[i+1+j+1] = min(dp[i+1+j+1],1+dp[i-j]);
}
return dp[n];
}
};