最后更新于
最后更新于
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回符合要求的最少分割次数。
示例:
输入: "aab" 输出: 1 解释: 进行一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。
回溯的思路同一样. 但由于要求返回最少分割次数, 我们将每次分割看作深度搜索树向下推荐了一层, 因此DFS的过程还要传递当前的层数.
不用再记录所有可能的分割结果, 而是需要维护一个最少层数, 当产生完整的分割结果时, 比较当前的分割结果推进了多少层, 如果比之前的少, 则更新方案, 否则不接受
剪枝规则增加, 如果当前递归层数已经大于已有方案的层数, 就可以停止递归而回溯了, 因为继续找下去的结果肯定也是无用的
为了让最小层数尽快出现, 增加剪枝效率, 迭代时首先考虑最长的分割方案, 然后将分割子字符串逐渐缩小
但回溯的方法时间复杂度依然很高, python提交超时.
定义一位状态数组dp[i]代表的意思是将[0, i](包括i)代表的子字符串, 分割成一些子串, 使每个子串都是回文串, 对应的最小分割次数. 因此题目最后的答案就是dp[n - 1], n是字符串的长度.
初始化dp[0], 由于是第一个字符, 不需要分割就是一个回文串, 因此对应的分割次数为0.
对于dp[i]的递推, 如果[j, i]是一个回文串, 那么有dp[i] = dp[j] + 1. 可能有多个后缀都是回文串, 因此要逐位遍历, 判断对应后缀是否是回文子串, 记录最小的结果, 及dp[i] = min(dp[i], dp[j] + 1).
另外还有两个点:
计算dp[i], 还要判断[0, i]整个子串是否是回文串, 如果是, 也不用分割, 对应的dp[i]为0, 且可以剪枝, 不再继续搜索下去了
在初始化时将每个位置的dp[i]置为一个很大的值, 方便统一判断
判断s[j, i]是否是回文串的方法, 可以使用同中动态规划的方法, 提前计算好每两个位置的结果. 可以是简单将字符串与反转后的字符串比较, 只不过这样时间复杂度高一些.
动态规划: