我们设 dp[i] 为串 s[0…i] 分割成全是回文的串所要求的最小次数。要计算 dp[i],我们可尝试枚举一下 s[0…i] 中分割出的最后一个回文串。设割点为 j,那么分割出的最后一个回文串就是 s[j+1…i]。要想确定 dp[i],我们就需要让 j 在区间 [0, i] 上从小到大遍历,找出使得 dp[i] 最小的那个分割点,即 dp[i] 从 dp[j] 转移而来,附加一次分割次数。
当然,若串 s[0…i] 本身就是回文串,就不必分割了,dp[i]=0。
核心代码如下:
if(s[0...i]是回文串) {
dp[i] = 0;
继续求dp[i+1];
}
for(int j = 0; j < i; j ++) {
if(s[j + 1...i]是回文串)
dp[i] = min(dp[i], dp[j] + 1);
}
如何判断 s[j + 1…i] 是回文串呢?在#647中已经写过了,直接搬过来就好了。
完整代码如下:
class Solution {
public:
int minCut(string s) {
int n = s.length();
vector<vector<bool>> dp1(n, vector<bool>(n, false)); // dp1即为记录s的某个区间的子串是否为回文的dp数组
for(int i = n - 1; i >= 0; i --) {
for(int j = i; j < n; j ++) {
if(s[i] != s[j]) {
dp1[i][j] = false;
} else {
if(j - i <= 2) {
dp1[i][j] = true;
} else if(dp1[i + 1][j - 1]) {
dp1[i][j] = true;
}
}
}
}
vector<int> dp2(n, INT_MAX); // dp2为本题的核心逻辑
dp2[0] = 0;
for(int i = 1; i < n; i ++) {
if(dp1[0][i]) { // 当串s[0...i]本身就是回文串时,不必分割
dp2[i] = 0;
continue;
}
for(int j = 0; j < i; j ++) {
if(dp1[j + 1][i])
dp2[i] = min(dp2[i], dp2[j] + 1);
}
}
return dp2[n - 1];
}
};
博主你好,你的网站做得真好,可以跟你换个友链吗?
你的网站是什么性质的呢