文章目录
- 1. 解题思路
- 1.1 创建dp表
- 1.2 状态转移方程
- 1.3 提前求出所有子串是否是回文串
- 2. 整体代码
1. 解题思路
1.1 创建dp表
这道题我们使用动态规划的方法来解,首先创建一个大小为字符串长度的dp表。dp[i] 表示 s[0, i] 的字符串最小划分多少次可以全划分为回文串。
1.2 状态转移方程
求状态转移方程,我们要考虑两种情况。s[0, i] 的字符串是回文串和不是回文串的情况。
注意,这里假设我们已经知道了哪段字符串是不是回文串,至于是如何知道的后面会说。
- 如果s[0, i]是回文串,那么问题很简单,不用切割就行,即dp[i] = 0;
- 如果s[0, i]不是回文串,我们要新增一个变量 j ,j 的范围为 (0, i],这里说明一些j的边界情况,j 要大于0的原因是 j 为0的情况即不用分割s[0, i]的情况(即s[0, i]为回文串的情况),j 为 i 的情况即 s[0, i-1] 中找不到从0开始且为回文串的情况。用这个 j 变量,我们遍历 j 的情况,j 是小于等于 i 的,那么 dp[j-1] 的值我们是知道的。如果从 j 到 i 的字符串是回文串,那么我们就令 dp[i] = min(dp[i], dp[j - 1] + 1); 遍历所有 j 的情况,就能求出 dp[i] 的最小值了。
1.3 提前求出所有子串是否是回文串
这个我在之前的博客就已经讨论过了,具体可见这篇文章。
2. 整体代码
class Solution {
public:
int minCut(string s) {
int n = s.size();
// 求出所有子串是否为回文串
vector<vector<bool>> isPal(n, vector<bool>(n));
for (int i = n - 1; i >= 0; --i)
for (int j = i; j < n; ++j)
if (s[i] == s[j])
isPal[i][j] = i + 1 < j ? isPal[i+1][j-1] : true;
// 创建dp表,由于是求最小值,可以先将所有位置初始化为最大
vector<int> dp(n, INT_MAX);
for (int i = 0; i < n; ++i)
{
if (isPal[0][i]) dp[i] = 0;
else
{
for (int j = 1; j <= i; ++j)
if (isPal[j][i]) dp[i] = min(dp[i], dp[j-1] + 1);
}
}
return dp[n-1];
}
};