1278. 分割回文串 III
大约 4 分钟
---
1278. 分割回文串 III
- 标签:字符串、动态规划
- 难度:困难
题目链接
题目大意
描述:给定一个字符串 和一个整数 。
要求:将字符串 分割成 个非空子串,使得每个子串都变成回文串所需修改的最少字符数。修改操作是指将字符串中的某个字符改为任意其他字符。
说明:
- 。
- 中只包含小写英文字母。
示例:
- 示例 1:
输入:s = "abc", k = 2
输出:1
解释:可以将 "abc" 分割成 "ab" 和 "c",将 "ab" 改成 "aa"(修改 1 个字符)得到回文串。或者分割成 "a" 和 "bc",将 "bc" 改成 "cc"。- 示例 2:
输入:s = "aabbc", k = 3
输出:0
解释:直接分割为 ["aa","bb","c"],每个子串已经是回文串,无需修改。解题思路
思路 1:动态规划
1. 阶段划分
这是一个将字符串切成 段的划分型 DP。先计算任意子串 变成回文串需要修改的次数,然后再用 DP 求解最小总修改次数。
阶段按"已经处理到的位置"和"已经切成的段数"划分。
2. 定义状态
第一步:定义 表示将子串 (从 到 ,包含两端)变成回文串所需的最少修改次数。
第二步:定义 表示将 的前 个字符()分割成 个子串所需的最少总修改次数。最终答案为 。
3. 状态转移方程
的转移:对于子串 ,如果两端的字符 ,则需要修改其中一个(1 次),中间的字符变成回文串需要 次:
的转移:将前 个字符分成 段,可以枚举最后一段的起始位置 (即最后一段为 ):
其中 从 到 (因为前 段至少需要 个字符)。
4. 初始条件
- (单字符本身就是回文)。
- 如果 ,否则为 (两个字符)。
- 。
- (初始化为较大值)。
5. 最终结果
。
6. 结合示例走一遍
先计算 :
- :两端 → (将 改成 或将 改成 )
- : →
- :
- : →
计算 :
- :
- :
- ("ab" 整体变回文需 1 次)
- ("a"+"b" 各需 0 次)
- :
- ("abc" 整体变回文需 1 次)
结果为 。
思路 1:代码
class Solution:
def palindromePartition(self, s: str, k: int) -> int:
n = len(s)
# 计算 cost[i][j]:s[i..j] 变成回文串的最小修改次数
cost = [[0] * n for _ in range(n)]
for length in range(2, n + 1): # 子串长度
for i in range(n - length + 1):
j = i + length - 1
# 两端字符不同则需要修改一次
cost[i][j] = cost[i + 1][j - 1] + (0 if s[i] == s[j] else 1)
# dp[i][j]:前 i 个字符分成 j 段的最小修改次数
dp = [[float('inf')] * (k + 1) for _ in range(n + 1)]
dp[0][0] = 0
for i in range(1, n + 1):
# 最多分成 min(i, k) 段
for j in range(1, min(i, k) + 1):
# 枚举最后一段的起始位置 m
for m in range(j - 1, i):
dp[i][j] = min(dp[i][j],
dp[m][j - 1] + cost[m][i - 1])
return dp[n][k]思路 1:复杂度分析
- 时间复杂度:,其中 是字符串长度。计算 需要 ,计算 需要 ,最坏 。,,在 Python 中可顺利通过。
- 空间复杂度:,存储 数组和 数组。