class Solution:
def partition(self, s: str) -> List[List[str]]:
n = len(s)
# dp[i][j]表示s[i..j]是否为回文串,其中空串、单个字符均为回文串
dp = [[True] * n for _ in range(n)]
# 从后往前遍历,确定哪些子串为回文串
for i in range(n - 1, -1, -1):
for j in range(i + 1, n):
# dp[i][j]表示s[i..j]为回文串:
# 当且仅当s[i]与s[j]相同 且 s[i+1..j-1]为回文串
dp[i][j] = (s[i] == s[j]) and dp[i + 1][j - 1]
res = []
ans = []
def dfs(i):
# 下标达到n,表示遍历完所有字符,则记录下当前的结果
if i == n:
res.append(ans[:])
return
# 使用回溯法来获取s[i]到s[n-1]中所有的回文串组合
for j in range(i, n):
if dp[i][j]:
ans.append(s[i:j+1])
dfs(j + 1)
ans.pop()
dfs(0) # 从下标0开始遍历
return res
132. 分割回文串 II
class Solution:
def minCut(self, s: str) -> int:
n = len(s)
# g[i][j]表示s[i..j]是否为回文串,其中空串、单个字符均为回文串
g = [[True] * n for _ in range(n)]
# 从后往前遍历,确定哪些子串为回文串
for i in range(n - 1, -1, -1):
for j in range(i + 1, n):
# g[i][j]表示s[i..j]为回文串:
# 当且仅当s[i]与s[j]相同 且 s[i+1..j-1]为回文串
g[i][j] = (s[i] == s[j]) and g[i + 1][j - 1]
# dp[i]表示字符串的前缀子字符串s[0..i]的最少分割次数
dp = [float("inf")] * n
for i in range(n):
# 若s[0..i]本身就是回文串,则无需分割,即分割次数为0
if g[0][i]:
dp[i] = 0
# 若s[0..i]不是回文串,则考虑s[0..i]中是否存在某一个子串s[j+1..i]是回文串,
# 若存在s[j+1..i]是回文串,那么f[i]就可以从f[j]附加1次额外的分割次数转移而来
else:
for j in range(i):
if g[j + 1][i]:
dp[i] = min(dp[i], dp[j] + 1)
return dp[n - 1]
1278. 分割回文串 III
class Solution:
def palindromePartition(self, s: str, k: int) -> int:
# 表示将s[i..j]子串变成回文串,最少需要修改的字符数,使用双指针来计算
def cost(l, r):
ret, i, j = 0, l, r
while i < j:
ret += (0 if s[i] == s[j] else 1)
i += 1
j -= 1
return ret
n = len(s)
f = [[10**9] * (k + 1) for _ in range(n + 1)]
f[0][0] = 0
for i in range(1, n + 1):
# j表示分割多少次
for j in range(1, min(k, i) + 1):
if j == 1:
f[i][j] = cost(0, i - 1)
else:
# 枚举第 j 个回文串的起始位置 m
for m in range(j - 1, i):
f[i][j] = min(f[i][j], f[m][j - 1] + cost(m, i - 1))
return f[n][k]
1745. 回文串分割 IV
class Solution:
def checkPartitioning(self, s: str) -> bool:
n = len(s)
dp = [[False] * n for _ in range(n)]
# 单个字符一定为回文串
for i in range(n):
dp[i][i] = True
# 区间DP时此处i以倒序遍历
for i in range(n-2,-1,-1):
for j in range(i+1,n):
# 若为2个字符的回文串,则只需考虑这2个字符是否相同
if j == i+1:
dp[i][j] = (s[i] == s[j])
# 否则还需考虑s[i+1...j-1]是否为回文串
else:
dp[i][j] = (s[i] == s[j]) and dp[i+1][j-1]
# 判断s[0...i], s[i+1...j], s[j...n-1]是否为回文串
for i in range(0,n-2):
# 若前i个字符的组成的子字符串s[0...i]不是回文串,则跳过
if not dp[0][i]:
continue
# 判断s[i+1...j], s[j...n-1]是否为回文串
for j in range(i+1,n-1):
if dp[i+1][j] and dp[j+1][n-1]:
return True
return False