题目描述
给你一个字符串 s
,请你将s
分割成一些子串,使每个子串都是回文。
返回符合要求的 最少分割次数 。
样例
输入:s = "aab"
输出:1
解释:只需一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。
算法
动态规划
f(i)表示的是以i结尾的字符串所包含回文子串的数量
0-i 划分为 0-k-1(以k-1结尾包含回文串的最小数量)、k-i(最后一段)
即递推式:f[i] = min(f[k - 1] + 1, f[i])
!因为我这里下标是从0开始的,所以当k==0时要特判一下
不加预处理优化会将时间复杂度划至 O ( n 3 ) O(n^3) O(n3),使用与处理后会缩减至 O ( n 2 ) O(n^2) O(n2)
时间复杂度
O ( n 2 ) O(n^2) O(n2)
Java 代码
class Solution {
String s;
List<String> part = new ArrayList<>();
boolean[][] f;
int[] dp;
int len;
int ans;
final int INF = 0x3f3f3f3f;
public int minCut(String _s) {
s = _s;
len = s.length();
f = new boolean [len][len];
dp = new int [len];
for (int j = 0; j < len; j ++ ) {
dp[j] = INF; // 顺带初始化dp数组
for (int i = 0; i <= j; i ++ ) {
if (i == j) f[i][j] = true;
else {
if (s.charAt(i) == s.charAt(j) && (i + 1 > j - 1 || f[i + 1][j - 1] == true)) f[i][j] = true;
}
}
}
for (int i = 0; i < len; i ++ ) {
for (int k = 0; k <= i; k ++ ) {
if (f[k][i] == true) { // 因为先前的预处理缩减了一层循环
if (k == 0)
dp[i] = Math.min(0 + 1, dp[i]);
else
dp[i] = Math.min(dp[k - 1] + 1, dp[i]);
}
}
}
return dp[len - 1] - 1; // 最终要求的结果是间隔数
}
}