分割回文串(2) | 刷题打卡

149 阅读2分钟

Leetcode 132. 分割回文串 II,难度:Hard
原题请戳这里

题目描述

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。

返回符合要求的 最少分割次数

示例1:

输入:s = "aab"
输出:1
解释:只需一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。

示例2:

输入:s = "a"
输出:0

示例3:

输入:s = "ab"
输出:1

提示:

  • 1 <= s.length <= 2000
  • s 仅由小写英文字母组成

思路分析

看到关键字“最少”,求极值问题,立即想到动态规划来解决。 设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 春招闯关活动」, 点击查看 活动详情