LeetCode 6236. 不重叠回文子字符串的最大数目
Hash + DP
const int N = 2000 + 10;
typedef unsigned long long ULL;
class Solution {
public:
ULL p[N], sin[N], cos[N], pow = 131;
bool check(int l, int r, int n)
{
if(sin[r] - sin[l] * p[r - l] == cos[n - l] - cos[n - r] * p[r - l])
return true;
return false;
}
int maxPalindromes(string s, int k) {
int n = s.size();
p[0] = 1;
for(int i = 1; i < n; i ++)
p[i] = p[i - 1] * pow;
cos[0] = sin[0] = 0;
for(int i = 0; i < n; i ++)
{
sin[i + 1] = sin[i] * pow + (s[i] - 'a' + 1);
}
reverse(s.begin(), s.end());
for(int i = 0; i < n; i ++)
{
cos[i + 1] = cos[i] * pow + (s[i] - 'a' + 1);
}
vector<int> f(n + 1);
for (int i = 1; i <= n; i++) {
for (int j = 0; j < i; j++) {
if (i - j < k)
f[i] = max(f[i], f[j]);
else {
f[i] = max(f[i], check(j, i, n) + f[j]);
}
}
}
return f[n];
}
};
纯 DP
const int N = 2010;
class Solution {
public:
bool g[N][N] = {false}; // i,j 为回文串
int f[N] = {0}; //前i个字母 不重叠 的子字符串数量
int maxPalindromes(string s, int k) {
int n = s.size();
for(int len = 1; len <= n; len ++)
{
for(int i = 1; i + len - 1 <= n; i ++)
{
int j = i + len - 1;
if(len == 1)
g[i][j] = true;
else if(s[i - 1] == s[j - 1] && (len == 2 || g[i + 1][j - 1]))
g[i][j] = true;
}
}
for(int i = 1; i <= n; i ++)
for(int j = 0; j < i; j ++)
{
if(i - j < k)
f[i] = max(f[i], f[j]);
else
f[i] = max(f[i], f[j] + g[j + 1][i]);
}
return f[n];
}
};
中心扩展DP
class Solution:
def maxPalindromes(self, s: str, k: int) -> int:
n = len(s)
# 奇回文 : n个回文中心
# 偶回文 :n-1个回文中心
f = [0] * (n + 1)
for i in range(2 * n - 1):
l = i // 2
r = l + i % 2
f[l + 1] = max(f[l], f[l + 1])
while l >= 0 and r < n and s[l] == s[r]:
if r - l + 1 >= k:
f[r + 1] = max(f[r + 1], f[l] + 1)
l -= 1
r += 1
return f[n]