Leetcode 132. 分割回文串 II,难度:Hard。
原题请戳这里。
题目描述
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。
返回符合要求的 最少分割次数 。
示例1:
输入:s = "aab"
输出:1
解释:只需一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。
示例2:
输入:s = "a"
输出:0
示例3:
输入:s = "ab"
输出:1
提示:
1 <= s.length <= 2000s仅由小写英文字母组成
思路分析
看到关键字“最少”,求极值问题,立即想到动态规划来解决。
设f(i)表示S[0...i]个字符的最少分割次数,为求得f(i),可以考虑枚举 S[0...i] 分割出的最后一个回文串,这样我们就可以写出状态转移方程:f(i) = f(j) + 1,其中0 <= j < i,如果能保证s[j+1, i]是一个回文串,那么f(i)就可以从f(j)转移而来。另外,如果S本身就是回文串,f(i) = 0。
接下来需要解决的就是如何判断某个子串是回文串,这个可以借助131. 分割回文串,也是使用动态规划进行预处理,将S的每个子串是否是回文串先求出来。这样只需要 O(1) 的时间就可以判断任意 s[i..j] 是否为回文串了。通过动态规划计算出所有的 f 值之后,最终的答案即为 f[n-1],其中 n 是字符串 S 的长度
AC代码
var minCut = function(s) {
const n = s.length;
const g = new Array(n).fill(0).map(() => new Array(n).fill(true));
for (let i = n - 1; i >= 0; --i) {
for (let j = i + 1; j < n; ++j) {
g[i][j] = s[i] == s[j] && g[i + 1][j - 1];
}
}
const f = new Array(n).fill(Number.MAX_SAFE_INTEGER);
for (let i = 0; i < n; ++i) {
if (g[0][i]) {
f[i] = 0;
} else {
for (let j = 0; j < i; ++j) {
if (g[j + 1][i]) {
f[i] = Math.min(f[i], f[j] + 1);
}
}
}
}
return f[n - 1];
};
总结
本题相似题目:
用到的技巧
- 两次动态规划,其中,求出每个子串是否是回文串已经是一个模板了。
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情