132. Palindrome Partitioning II
回文串的题目,这道题可以利用我之前的一个优化方案,我们知道回文串中有一个非常讨厌的情况就是奇偶问题,我们可以通过修改原始串达到所有的串都是一个奇数串。当中的最长回文串里面是利用间隔之间添加‘#’使得字符串都是奇数个。这道题呢依然可以利用,同时当中的思想也和刚才那道最长回文串非常相似。考虑这么一个问题:
字符串s:aabac
现在我们有两种切法,第一种我们需要从aa之间切一刀,那么剩下的abac又是一个子问题,同理我们可以从ab之间切一刀,那么剩下的bac同样也是子问题。相信我这么说小伙伴已经知道这是一个DP问题了。再提一点为什么这里一开始我说有两种切法,是应为aa已经是一个回文串,那么他就有两种切法,因为aab这三个不是回文串在目前看来(因为我们不保证在后续的字符串中aab是一个回文串的一部分,仅当前来看)我们必须要进行切分。那么我们需要找到回文串,那么回文串有一个非常好的特性那就是对称,同时现在我们又将子串变成奇数个所以这个操作将会非常操作,我们利用一个一维数组DP来保存长度为n的字符串最多需要切多少次,也就是说长度为1的字符串仅需要切0次,长度为2的字符串仅需要1次,这是我们初始化的条件,那么具体代码如下:
class Solution {
public:
int minCut(string s) {
string c;
for (int i = 0; i < s.size(); i++)
{
c.push_back('#');
c.push_back(s[i]);
}
c.push_back('#');
int n = c.size();
vector<int>dp(n + 1, 0);
for (int i = 0; i <= n ; i++)
dp[i] = i / 2 - 1;
for (int i = 0; i <= n; i++)
for (int j = 0; j <= i && i + j < n && c[i + j] == c[i - j]; j++)
dp[i + j + 1] = min(dp[i + j + 1], dp[i - j] + 1);
return dp[n];
}
};
我们仔细看这个代码我们首先对初始字符串进行奇数化,通过添加‘#’,同时定义DP数组进行初始化,那这里为什么是i/2呢,我相信小伙伴已经明白了,这里的‘#’实际上并不存在,也就是我们对 #a 在#与a之间切一刀是不存在的,所以我们进行了除2操作。那么下面的for循环首先我们需要判断说那个条件,第一是我们关于i点对称进行扫描,那么边界问题需要注意,这个在for循环里写的已经很清楚了,那么最后dp[ i + j + 1] = min(dp[i + j + 1], dp[i - j] + 1)这个是什么思想呢,也就是说我们对于这个回文串已经知道关于i点对称那么我们对于这个回文串是不进行切分,我相信通过过看代码已经知道。