132. 分割回文串 II
给你一个字符串 s
,请你将 s
分割成一些子串,使每个子串都是回文。
返回符合要求的 最少分割次数 。
示例 1:
输入:s = "aab"
输出:1
解释:只需一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。
示例 2:
输入:s = "a"
输出:0
示例 3:
输入:s = "ab"
输出:1
提示:
1 <= s.length <= 2000
s
仅由小写英文字母组成
方法一:动态规划 + 动态规划
解题思路
昨天的题 131. 分割回文串 的升级版。
- 依然采用「动态规划」预处理字符串
s
,求出任意子串是否为回文串。 - 预处理完成后,得到处理结果
boolean dp[][]
,dp[i][j]
为true
表示子串s[i,j]
为回文串,反之不是回文串。 - 因为要求最少分割次数,我们可以用「动态规划」处理
dp
。动态规划三板斧:- 状态定义: 定义
int f[]
,f[i]
表示字符串角标为i
时,需要的最少分割次数。 - 初始化:根据提示
s
长度最长 2000,那么我们最多需要分割 1999 次,初始化的数字大于等于 1999 即可。 - 状态转移:当
dp[0][i] == true
,有f[i] = 0
;反之,需要遍历0 到 i
,求得最小的f[i]
。
- 状态定义: 定义
参考代码
public int minCut(String s) {
int n = s.length();
// 动态规划预处理 求出任意子串是否为回文串
boolean dp[][] = new boolean[n][n];
for (int j = 0; j < n; j++) {
for (int i = 0; i <= j; i++) {
if (s.charAt(i) == s.charAt(j) && (j - i <= 2 || dp[i + 1][j - 1])) {
dp[i][j] = true;
}
}
}
// 在预处理的基础上,继续动态规划求出最少分割次数
int[] f = new int[n];
Arrays.fill(f, 2000);
for (int i = 0; i < n; i++) {
if (dp[0][i]) {
f[i] = 0;
} else {
for (int j = 0; j < i; j++) {
if (dp[j + 1][i]) {
f[i] = Math.min(f[i], f[j] + 1);
}
}
}
}
return f[n - 1];
}