题目地址:
https://leetcode.com/problems/maximum-number-of-non-overlapping-palindrome-substrings/description/
给定一个长 n n n字符串 s s s和一个正整数 k k k。可以将 s s s中选取若干不重合子串,使得每个子串长度大于等于 k k k,并且都是回文串。问所有选法里子串个数的最大值。
先预处理一个bool数组
g
g
g,使得
g
[
i
]
[
j
]
g[i][j]
g[i][j]表示
s
[
i
:
j
]
s[i:j]
s[i:j]是否是回文串。接下来开一个数组
f
f
f,
f
[
i
]
f[i]
f[i]表示
s
s
s的前
i
i
i个字符最多能找到多少个不重合的回文子串且每个子串长度大于等于
k
k
k。分两种情况:
1、
s
[
i
−
1
]
s[i-1]
s[i−1]不属于最优方案的子串,此时
f
[
i
]
=
f
[
i
−
1
]
f[i]=f[i-1]
f[i]=f[i−1]。
2、
s
[
i
−
1
]
s[i-1]
s[i−1]属于最优方案的子串,那么由于最后一个子串长度大于等于
k
k
k,从而可以枚举最后一个子串的起始位置。但是其实只需要看最后个子串长度
k
k
k和
k
+
1
k+1
k+1的情况即可(即奇回文和偶回文两种可能)。因为如果再长的话,之前一定是取到了最大值的。
代码如下:
class Solution {
public:
int maxPalindromes(string s, int k) {
int n = s.size();
bool g[n + 1][n + 1];
memset(g, 1, sizeof g);
for (int len = 1; len <= n; len++)
for (int l = 0; l + len - 1 < n; l++) {
int r = l + len - 1;
if (len == 1)
g[l][r] = true;
else if (len == 2)
g[l][r] = s[l] == s[r];
else
g[l][r] = s[l] == s[r] ? g[l + 1][r - 1] : false;
}
vector<int> f(n + 1, 0);
for (int i = k - 1; i < n; i++) {
f[i + 1] = f[i];
if (g[i - k + 1][i]) f[i + 1] = max(f[i + 1], 1 + f[i - k + 1]);
if (i - k >= 0 && g[i - k][i]) f[i + 1] = max(f[i + 1], 1 + f[i - k]);
}
return f[n];
}
};
时空复杂度 O ( n 2 ) O(n^2) O(n2)。