[和小菜鸡一起刷题(python)] LeetCode 132. 分割回文串 II (Palindrome Partitioning II)

LeetCode 132. 分割回文串 II (Palindrome Partitioning II)

原题

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

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

示例:

输入: “aab”
输出: 1
解释: 进行一次分割就可将 s 分割成 [“aa”,“b”] 这样两个回文子串。

思路

若是按照之前131题回文分割的方法,求出所有的可能,再统计出最小的分割数,会超出时间限制无法通过。此题不要求求出具体分割方案,可以考虑使用动态规划求解。
假设输入字符串为’aabac’:
|a  |a  |b  |a  |c  |
0 1  2  3  4  5
我们可以创建一个数组res来存储每个位置的初始最小分割次数,也就是当字符串中完全没有回文串时的最大分割次数,即[-1,0,1,2,3,4]。
如何进一步更新每个位置需要的分割次数呢?我们先来依次遍历每个分割位,实验观察一下res的变化。
在位置0时,不做更新。
在位置1时,不做更新。
在位置2时,发现’aa’可以构成回文串,res更新为[-1,0,0,2,3,4]。
在位置3时,最小分割为’aa’和’b’,需要一次分割,res更新为[-1,0,0,1,3,4]。
在位置4时,最小分割为’a’和’aba’,需要一次分割,res更新为[-1,0,0,1,1,4]。
在位置5时,最小分割为’a’,‘aba’和’c’,需要两次分割,res更新为[-1,0,0,1,1,2]。
可以得出一下结论,当我们在分割位i时,若s[j:i]为回文串,那么res[i]的分割次数为在分割位j的次数res[j] + 1。题目要求是最少的次数,因此j遍历0到i-1的所有位置,求出res[i]的最小值。最后我们只要返回res[-1]就是我们要的答案。
到这里此题我们差不多已经解决一半了,为什么是一半呢?因为如果每次都判断s[j:i]是否是回文串会有很多次重复判断,从而导致超时。解决方法是空间换时间,创建一个二维数组if_palindrome来存储所有子字符串是否是回文串。这个二维数组的赋值操作可以在上述循环中同时进行。若s[j:i]首尾相等,中间部分也是回文串或者s[j:i]的长度小于等于2(即中间部分为空),则s[j:i]为回文串,if_palindrome[j][i] = True。
具体请参考以下代码。

代码

class Solution(object):
    def minCut(self, s):
        """
        :type s: str
        :rtype: int
        """
        if len(s) == 0:
            return 0
        else:
            res = [i for i in range(-1, (len(s)))]
            if_palindrome = [[False] * (len(s) + 1) for _ in range(len(s) + 1)]
            for i in range(1, len(s) + 1):
                for j in range(i):
                    if s[i-1] == s[j] and (i - j <= 2 or if_palindrome[j + 1][i - 1]):
                        if_palindrome[j][i] = True
                        res[i] = min(res[j] + 1, res[i])
            return res[-1]
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值