LeetCode之Palindrome Partitioning II

Given a string s, partition s such that every substring of the partition is a palindrome.

Return the minimum cuts needed for a palindrome partitioning of s.

For example, given s = "aab",
Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.

题目大意是给定一个字符串,你可以对其任意划分,不过要保证每一个字串都是回文串。问所需的最小划分是多少?

看到这个题想也不想就用动态规划,先写一个ispal()的方法判断其是否为回文串,用一个cuts的二维数组来存其字串的最小划分(cuts[i][j]表示第i个字符开始第j个字符结束(包含第j个字符)的字串的最小划分)运用动态规划思路如下:

cuts[i][i]=0

cuts[i][j]= 0 if s[i:j+1]是回文串

min(cuts[i][k-1]+cuts[k][j]+1) (i+1<=k<=j)

写出代码如下(时间复杂度O(n^4)):

class Solution:
    @staticmethod
    def ispal(s):
        if len(s)%2==0:
            s1=s[:len(s)//2]+' '+s[len(s)//2:]
        else:
            s1=s
        mid=len(s)//2
        for i  in range(1,mid+1):
            if s1[mid-i]!=s1[mid+i]:
                return False
        return True
    @classmethod
    # @param s, a string
    # @return an integer
    def minCut(self, s):
        cuts=[[len(s)+1 for col in range(len(s))] for row in range(len(s))]
        for i in range(0,len(s)):
            cuts[i][i]=0
        for i in range(1,len(s)):
            for j in range(0,len(s)-i):
                'solve cuts[j][j+i]'
                if self.ispal(s[j:j+i+1]):
                    cuts[j][j+i]=0
                else:
                    for k in range(j+1,j+i+1):
                        if cuts[j][j+i]>cuts[j][k-1]+cuts[k][j+i]+1:
                            cuts[j][j+i]=cuts[j][k-1]+cuts[k][j+i]+1
        return cuts[0][len(s)-1]

if __name__=="__main__":
    s=Solution()
    print(s.minCut("aab"))

果然超时了

  Status: 
Time Limit Exceeded
 
Submitted:  3 hours, 18 minutes ago
Last executed input: "adabdcaebdcebdcacaaaadbbcadabcbeabaadcbcaaddebdbddcbdacdbbaedbdaaecabdceddccbdeeddccdaabbabbdedaaabcdadbdabeacbeadbaddcbaacdbabcccbaceedbcccedbeecbccaecadccbdbdccbcbaacccbddcccbaedbacdbcaccdcaadcbaebebcceabbdcdeaabdbabadeaaaaedbdbcebcbddebccacacddebecabccbbdcbecbaeedcdacdcbdbebbacddddaabaedabbaaabaddcdaadcccdeebcabacdadbaacdccbeceddeebbbdbaaaaabaeecccaebdeabddacbedededebdebabdbcbdcbadbeeceecdcdbbdcbdbeeebcdcabdeeacabdeaedebbcaacdadaecbccbededceceabdcabdeabbcdecdedadcaebaababeedcaacdbdacbccdbcece"

那么就递归吧:

不管怎么划分我们都要切第一刀,而且第一刀必然要保证前面的串是回文串。那么我们就找从索引0开始的所有回文子串,再对剩下的子串调用递归,找出所有可能的最小划分。如果整个串是回文串,那么返回0。

核心代码如下:

    def minCut(self, s):
        min_cut=0xffffffff
        if Solution.ispal(s):
            return 0
        for i in range(1,len(s)):
            if Solution.ispal(s[:-i]):
                other_cut=self.minCut(s[-i:])
                if(other_cut+1<min_cut):
                    min_cut=other_cut+1
        return min_cut

  Status: 
Time Limit Exceeded
 
Submitted:  1 hour, 10 minutes ago
Last executed input: "apjesgpsxoeiokmqmfgvjslcjukbqxpsobyhjpbgdfruqdkeiszrlmtwgfxyfostpqczidfljwfbbrflkgdvtytbgqalguewnhvvmcgxboycffopmtmhtfizxkmeftcucxpobxmelmjtuzigsxnncxpaibgpuijwhankxbplpyejxmrrjgeoevqozwdtgospohznkoyzocjlracchjqnggbfeebmuvbicbvmpuleywrpzwsihivnrwtxcukwplgtobhgxukwrdlszfaiqxwjvrgxnsveedxseeyeykarqnjrtlaliyudpacctzizcftjlunlgnfwcqqxcqikocqffsjyurzwysfjmswvhbrmshjuzsgpwyubtfbnwajuvrfhlccvfwhxfqthkcwhatktymgxostjlztwdxritygbrbibdgkezvzajizxasjnrcjwzdfvdnwwqeyumkamhzoqhnqjfzwzbixclcxqrtniznemxeahfozp"

依然超时,时间复杂度为O(n^3)

用动态规划改写一下,cuts[i]表示从0开始到i结束的字串的最小划分

cut[0]=0

cut[i]= 0 if s[0:i+1]为回文串

min(1+cuts[j-1])(1<=j<=i)

写出代码如下,依然O(n^3)

    def minCut(self, s):
        if len(s)==0:
            return 0
        cuts=[0xffffffff]*len(s)
        cuts[0]=0
        for i in range(1,len(s)):
            if self.ispal(s[0:i+1]):
                cuts[i]=0
            for j in range(1,i+1):
                if self.ispal(s[j:i+1]) and 1+cuts[j-1]<cuts[i]:
                    cuts[i]=1+cuts[j-1]
        return cuts[len(s)-1]


依然不出意外地超时:

  Status: 
Time Limit Exceeded
 
Submitted:  59 minutes ago
Last executed input: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
不过这个大概是这题对时间复杂度要求最高的用例了

这个方法代码看上去非常像O(n^2)的代码,ispal函数内部隐藏了一层O(n)

如果能将ispal函数变成常数时间内返回某个字串是否为回文串,那么不就可以O(n^2)解决?

我当然不是针对任意字符串输入啦,而是预先对传给minCut函数的字符串s进行打表,预先算好它每一个字串是否为回文串,可以在O(n^2)搞定

具体算法如下:

        for i in range(len(s)):
               ispal[i][i]=True
        for i in range(1,len(s)-1):
            j=1
            while i-j>=0 and i+j<len(s):
                if(s[i-j]==s[i+j]):
                    ispal[i-j][i+j]=True
                    j=j+1
                else:
                    break
        for i in range(0,len(s)-1):
            start=i
            end=i+1
            while start>=0 and end<len(s):
                if(s[start]==s[end]):
                    ispal[start][end]=True
                    start=start-1
                    end=end+1
                else:
                    break

我们用ispal[i][j]存以第i个字符开始第j个字符结束的字串是否为回文串

先给所有的元素置False,再给ispal[i][i]置True,因为只有一个字符组成的字符串一定是回文串

接着求所有奇数个字符组成的回文串

我们再选定一个字符为中心,以这个字符开始往两边扩展,如果它两边的字符相同,那么这3个字符组成的串是回文串,ispal置True,继续扩展到5个字符……只要有一对字符不同,就返回False,不继续扩展

再求所有偶数个字符组成的回文串

先选一个字符为start,再选start+1为end

如果s[start]==s[end],那么从start到end的字符组成的字串是回文串,置ispal[start][end] 为True,start往左走一位,end往右走一位,继续判断s[start]==s[end],一直到出现不等为止

最终代码如下:

class Solution:
    # @param s, a string
    # @return an integer
    def minCut(self, s):
        if len(s)==0:
            return 0
        ispal=[[False for col in range(len(s))] for row in range(len(s))]
        for i in range(len(s)):
               ispal[i][i]=True
        for i in range(1,len(s)-1):
            j=1
            while i-j>=0 and i+j<len(s):
                if(s[i-j]==s[i+j]):
                    ispal[i-j][i+j]=True
                    j=j+1
                else:
                    break
        for i in range(0,len(s)-1):
            start=i
            end=i+1
            while start>=0 and end<len(s):
                if(s[start]==s[end]):
                    ispal[start][end]=True
                    start=start-1
                    end=end+1
                else:
                    break
        cuts=[0xffffffff]*len(s)
        cuts[0]=0
        for i in range(1,len(s)):
            if ispal[0][i]:
                cuts[i]=0
            for j in range(1,i+1):
                if ispal[j][i] and 1+cuts[j-1]<cuts[i]:
                    cuts[i]=1+cuts[j-1]
        return cuts[len(s)-1]

时间复杂度为O(n^2),AC

Submission Details

28 / 28 test cases passed.
Status: 
Accepted
Runtime:  1784 ms
Submitted:  46 minutes ago




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值