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
|