题目
给你一个字符串 s
,请你将 s
分割成一些子串,使每个子串都是回文。
返回符合要求的 最少分割次数 。
提示:
-
1 <= s.length <= 2000
-
s
仅由小写英文字母组成
题解
拆解问题
如果已经求得一个子串的最少分割次数,是可以推导出整个串的最少分割次数。
- 要保证分割次数最少,先检查整个串s是不是回文。
- 如果是,就不用分割了,分割次数是0。
- 如果s不是回文,需要在0到
n - 1
(n为s长度)中找一个分割位置i
。- 如果
s[0: i]
的最少分割次数已经知道(0 <= i < n)
,同时s[i + 1:]
是回文,说明在s[0: i]
的最少分割次数基础上还要再多分割一次才能完成整个串的分割,那么整个字符串s的最少分割次数就是s[0: i]
的最少分割次数 + 1。 - 而
s[0: i]
的最少分割次数其实是需要把i
从0到n - 2
全部遍历一遍才知道哪一种分割的次数是最小的,那么s[0: i]
的最少分割次数的求法,跟上述过程一样,可以递推。
- 如果
注:s[0: i]是python中截取子串的表示方法,表示截取第0位到第i位的字符)
状态转移方程
令dp[i]
表示s[0: i]
的最少分割次数。
如果s[0: i]
就是回文,那么dp[i]
就是0。
如果s[0: i]
不是回文,但是它的一个子串s[0: j]
的最少分割次数已知(0 <= j < i
),并且s[j + 1: i]
是回文,则 dp[i] = dp[j] + 1
最终结果就是求dp[n - 1]
,从0开始递推就好了。
递推方程: dp[i] = min(dp[j]) + 1
,其中0 <= j < i
。
初始状态
- 初始状态
dp[0]
就是s[0: 0]
的最少分割次数,s[0: 0]
就是首字符,单个字符是回文串,所以不用分割,dp[0] = 0
。 - 最坏的情况就是每个字符都分割,因为每个单字符都是回文,最大的分割次数就是
n - 1
,可以给dp
数组初始化。
怎么快速判断s[i, j]是回文?
最好预处理整个s,把s的所有子串都判断一下是不是回文串,这样就可以做到O(1)的查表操作来快速判断了。
这里跟 131. 分割回文串 处理方式一样。
1 | class Solution { |
时间复杂度:O(n^2)
n 是字符串 s 的长度。
预处理计算s所有子串是否是回文和动态规划计算s最小分割次数的时间复杂度均为 O(n^2)。空间复杂度:O(n^2)
预处理计算s所有子串是否是回文需要O(n^2)的空间占用。
动态规划计算s最小分割次数需要O(n)的空间占用。