题目描述
Given a string s, partition s such that every substring of the partition is a palindrome.
Return the minimum cuts needed for a palindrome partitioning of s.
For example, given s =”aab”,
Return1since the palindrome partitioning[“aa”,”b”]could be produced using 1 cut.
分析思路
首先该问题是一个优化问题:如何分割字符串才能用最小的分割次数使得所有子串都是回文字符串(palindrome)
考虑以下思路:
- 最小的分割次数-> 得到的子串个数最少 -> 子串尽可能的长
- 对于一个回文串,去掉其头尾字符,依然还是回文串
- 将长度为n的字符串分割为n个子串(每个子串一个字符)必然满足子串是回文的要求
- 将长度为1的子串进行组合,尽量构成更长的回文子串
于是,问题可以转换为一个动态规划问题(自底向上的动态规划问题):
(1)初始状态下,假设需要进行n-1次分割(得到n个长度为1的子串-最小回文)
(2)用一个2维矩阵来描述,s.substr(k, j - k+1) 是否能构成回文子串
(3)依次解决子问题,前i个字符能实现的最简分割(构成最长回文子串的个数)(重点问题)
代码解答
class Solution{
public:
int minCut(string ss)
{
int len = ss.length(); // 求解字符串长度
// 用于描述s.substr(k, j - k+1) 是否能构成回文子串的矩阵
// flag[k][j] = true -》能构成回文子串
vector<vector<bool>> flag(len, vector<bool>(len,false));
// 用于记录最佳分割次数的vector
// 初始状态下,长为i的子串的最佳分割次数为:vec[i] = i-1
vector<int> vec(len+1);
for(int i = 0;i<len+1;++i){
vec[i] = i-1;
}
// 进入动态规划
for(int i = 0 ; i < len ; i++)
{
for(int j = 0; j <= i ; j++)
{
// ss中的ss[j]到ss[i]构成的子串(substr(j,i-j+1))能不能构成回文串?
// 注意判断条件中的i-j<2 :对于长度小鱼等于2的子串,只要ss[i]==ss[j]就可以构成初始子串
if(ss[i] == ss[j] && (i-j<2 || flag[j+1][i-1]==true)){
flag[j][i] = true;
//此时前i个字符的最佳分割或者为原分割次数vec[i+1],或为前j-1个字符的最佳分割次数+1
vec[i+1] = min(vec[i+1],vec[j]+1);
} //end of if
}//end of for(j)
}// end of for(i)
return vec[len];
} // end of func: minCut()
};// end of class