版权声明:本文为博主原创文章,未经博主允许不得转载。有事联系:[email protected] https://blog.csdn.net/qq_17550379/article/details/85482167
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回符合要求的最少分割次数。
示例:
输入: "aab"
输出: 1
解释: 进行一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。
解题思路
这个问题是之前问题的提高?Leetcode 131:分割回文串(最详细的解法!!!)
一个简单的动态规划问题。我们定义函数
表示s[:i]
的最小分割次数。我们我们只需要找到i
之前的一个位置j
,使得s[j:i]
是一个回文串,那么就可以得到这样的递推公式
class Solution:
def minCut(self, s):
"""
:type s: str
:rtype: int
"""
if not s:
return 0
s_len = len(s)
mem = [i for i in range(-1, s_len)]
for i in range(1, s_len + 1):
for j in range(i):
if s[j:i] == s[j:i][::-1]:
mem[i] = min(mem[i], mem[j] + 1)
return mem[-1]
恩,虽然通过了,但是我们这个算法的时间复杂度依旧非常高。其实这个问题就是最长回文子串
问题的变种。我们可以参考Leetcode 5:最长回文子串(最详细的解法!!!)最后的一种做法。我们首先建立r1
和r2
,分别表示偶数回文串的半径长度和奇数回文串的半径长度。然后我们遍历s
中的每个字符串,分别以每个字符串为圆心找到最长的回文串。假设圆心是i
,我们可以得到下面两个式子:
class Solution:
def minCut(self, s):
"""
:type s: str
:rtype: int
"""
if s == s[::-1]:
return 0
for i in range(1, len(s)):
if s[:i] == s[:i][::-1] and s[i:] == s[i:][::-1]:
return 1
mem = list(range(-1,len(s)))
for i in range(len(s)):
r1, r2 = 0, 0
while i-r1 >= 0 and i+r1 < len(s) and s[i-r1] == s[i+r1]:
mem[i+r1+1] = min(mem[i+r1+1],mem[i-r1]+1)
r1 += 1
while i-r2 >= 0 and i+r2+1 < len(s) and s[i-r2] == s[i+r2+1]:
mem[i+r2+2] = min(mem[i+r2+2],mem[i-r2]+1)
r2 += 1
return mem[-1]
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!