题目:
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。
返回符合要求的 最少分割次数 。
题解:
考虑 dp(字符串类型题目,经常用 dp)
dp[i] 为 字符串 0 到 i 的最少分割次数
那么我们如何利用之前的 dp[k](k < i) 呢
假如 字符串 k 到 i 为回文 (flag[k][i] == true),是不是 dp[i] = dp[k] + 1
建立状态转移方程 dp[i] = min(dp[0], … ,dp[i - 1](前提为dp[k][i] 为回文)) + 1
怎么快速得到 字符串 k 到 i 是否为回文呢(flag[k][i] == true)
进行预处理
如果 s[i] == s[j] && flag[i + 1][j - 1] 则 flag[i][j] 为 true(是回文)
两种遍历来预处理:
①
i 为子字符串的长度,j 为子字符串起点
bool flag[2005][2005] = { false };
for(int i = 0; i < s.size(); i++) {
for(int j = 0; j + i < s.size(); j++) {
if(i == 0) {
flag[j][j + i] = true;
}
else if(i == 1) {
if(s[j] == s[j + i]) flag[j][j + i] = true;
else flag[j][j + i] = false;
}
else {
flag[j][j + i] = (s[j] == s[j + i]) && flag[j + 1][j + i - 1];
}
}
}
②
从后往前预处理
vector<vector<int>> g(n, vector<int>(n, true));
for (int i = n - 1; i >= 0; --i) {
for (int j = i + 1; j < n; ++j) {
g[i][j] = (s[i] == s[j]) && g[i + 1][j - 1];
}
}
代码如下:
class Solution {
public:
bool flag[2005][2005] = { false };
int dp[2005] = { 0 };
int minCut(string s) {
for(int i = 0; i < s.size(); i++) {
for(int j = 0; j + i < s.size(); j++) {
if(i == 0) {
flag[j][j + i] = true;
}
else if(i == 1) {
if(s[j] == s[j + i]) flag[j][j + i] = true;
else flag[j][j + i] = false;
}
else {
flag[j][j + i] = (s[j] == s[j + i]) && flag[j + 1][j + i - 1];
}
}
}
for(int i = 0; i < s.size(); i++) {
dp[i] = INT_MAX;
if(flag[0][i] == true) {
dp[i] = 1;
}
else {
for(int j = 0; j < i; j++) {
if(flag[j + 1][i] == true) {
dp[i] = min(dp[i], dp[j] + 1);
}
}
}
}
return dp[s.size() - 1] - 1;
}
};