问题描述
给你一个字符串 s ,每个字符是数字 '1' 到 '9' ,再给你两个整数 k 和 minLength 。
如果对 s 的分割满足以下条件,那么我们认为它是一个 完美 分割:
s 被分成 k 段互不相交的子字符串。
每个子字符串长度都 至少 为 minLength 。
每个子字符串的第一个字符都是一个 质数 数字,最后一个字符都是一个 非质数 数字。质数数字为 '2' ,'3' ,'5' 和 '7' ,剩下的都是非质数数字。
请你返回 s 的 完美 分割数目。由于答案可能很大,请返回答案对 109 + 7 取余 后的结果。
一个 子字符串 是字符串中一段连续字符串序列。
示例 1:
输入:s = "23542185131", k = 3, minLength = 2
输出:3
解释:存在 3 种完美分割方案:
"2354 | 218 | 5131"
"2354 | 21851 | 31"
"2354218 | 51 | 31"
示例 2:
输入:s = "23542185131", k = 3, minLength = 3
输出:1
解释:存在一种完美分割方案:"2354 | 218 | 5131" 。
示例 3:
输入:s = "3312958", k = 3, minLength = 1
输出:1
解释:存在一种完美分割方案:"331 | 29 | 58" 。
提示:
1 <= k, minLength <= s.length <= 1000
s 每个字符都为数字 '1' 到 '9' 之一。
问题求解
dp[i][j]: 前j个字符划分成i段分割数目。
为了方便转移,我们将s可以从下标1开始,下标0表示前0个字符,方便转移。
核心的难点在于如何优化dp,这里使用了常用技巧前缀和优化来加速迭代进程。
class Solution:
def beautifulPartitions(self, s: str, k: int, minLength: int) -> int:
if k * minLength > len(s) or s[0] not in "2357" or s[-1] in "2357":
return 0
MOD = 10 ** 9 + 7
n = len(s)
s = "#" + s
dp = [[0] * (n + 1) for _ in range(k + 1)]
dp[0][0] = 1
for i in range(1, k + 1):
presum = 0
for j in range(i * minLength, n + 1):
if s[j - minLength + 1] in "2357" and s[j - minLength] not in "2357":
presum += dp[i - 1][j - minLength]
presum %= MOD
if s[j] not in "2357":
dp[i][j] += presum
return dp[k][n]
标签:分割,前缀,完美,minLength,2478,DP,字符串,2357,dp
From: https://www.cnblogs.com/hyserendipity/p/16928265.html