给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回符合要求的最少分割次数。
示例:
输入: “aab”
输出: 1
解释: 进行一次分割就可将 s 分割成 [“aa”,“b”] 这样两个回文子串。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/palindrome-partitioning-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:使用动态规划。
从最优策略的前提下关注最后一段回文串。设为:S[j...N-1]
,那么要知道整个字符串能划分成最少则还需要知道S
前j
个字符[0..j-1]
最少可以划分成几个回文串。(划分出了子问题)
初始条件:f[0] = 0
前0
个字符可以划分成0
个回文串个数。
用f[i]
表示前i
个字符S[0..i-1]
最少可以划分成的回文串个数。
则转移方程:
判断回文串:采用从中心向两边扩张的方法。(优化的话可以用马拉车)
class Solution {
public:
int minCut(string s) {
int n = s.size();
if(n == 0)
return 0;
vector<vector<bool>> isPalin(n,vector<bool>(n,false));
isPalin = calcPalin(s);
vector<int>f(n+1,0);
f[0] = 0;
for(int i = 1;i <= n;++i)
{
f[i] = INT_MAX;
for(int j = 0; j < i;++j)
{
if(isPalin[j][i - 1])//只要j到i-1是回文串 就更新
{
f[i] = min(f[i],f[j] + 1);
}
}
}
return f[n] - 1;//题目中求的是分割字符串次数 我们求出了能分出多少个字符串
//那么次数就是字符串个数减1
}
private:
vector<vector<bool>> calcPalin(const string& s)
{
int n = s.size();
vector<vector<bool>>f(n,vector<bool>(n,false));
int i;
int j;
//奇数情况
for(int c = 0; c < n; ++c)
{
i = j = c;
//生成回文串法检测回文串
while(i >= 0&&j < n && s[i] == s[j])
{
f[i][j] = true;
--i;
++j;
}
}
//偶数情况
for(int c = 0;c < n - 1;++c)
{
i = c;
j = c + 1;
while(i >= 0 && j < n && s[i] == s[j])
{
f[i][j] = true;
--i;
++j;
}
}
return f;
}
};