一、问题分析
这道题目要求我们计算将数字字符串分割成k个子串的"完美分割"方式数目。完美分割需要满足三个条件:
分成k段互不相交的子串
每个子串长度至少为minLength
每个子串首字符是质数(2,3,5,7),尾字符是非质数(1,4,6,8,9)
二、解题思路
我们可以使用动态规划来解决这个问题:
预处理质数判断数组
定义dp[i][j]表示前i个字符分成j段的完美分割数目
通过双重循环填充dp表
最终结果为dp[n][k]
class Solution {
public:
int beautifulPartitions(string s, int k, int minLength) {
const int MOD = 1e9 + 7;
int n = s.size();
// 预处理质数判断
auto isPrime = [](char c) {
return c == '2' || c == '3' || c == '5' || c == '7';
};
// 检查首尾字符是否满足条件
if (!isPrime(s[0]) || isPrime(s.bACk())) return 0;
// dp[i][j]表示前i个字符分成j段的方案数
vector<vector<int>> dp(n + 1, vector<int>(k + 1, 0));
dp[0][0] = 1;
for (int j = 1; j <= k; ++j) {
// 前缀和优化,避免重复计算
vector<int> prefix(n + 1, 0);
prefix[0] = dp[0][j - 1];
for (int i = 1; i <= n; ++i) {
prefix[i] = (prefix[i - 1] + dp[i][j - 1]) % MOD;
}
for (int i = 1; i <= n; ++i) {
if (i < minLength) continue;
if (!isPrime(s[i - 1]) && (i == n || isPrime(s[i]))) {
int start = max(0, i - minLength);
dp[i][j] = (dp[i][j] + prefix[start]) % MOD;
}
}
}
return dp[n][k];
}
};