1.首先肯定是如何求最长回文子串、
这篇博客写的挺好的: 传送门
还是很好理解的,根据id、mx推出i关于id的对称点
从而在以id为回文中心的情况下求出一部分以i为回文中心的回文串大小
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <utility>
#include <bitset>
#include <unistd.h>
using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define mst(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson ((rt << 1) | 1)
const int qq = 1e5 + 300;
const int INF = 1e9 + 10;
const int MOD = 1e9 + 7;
int p[qq];
string init (string st) {
string tmp = "$#";
for (int i = 0; i < (int)st.size(); ++i) {
tmp += st[i];
tmp += "#";
}
return tmp;
}
int manacher (string st, int *p) {
int id, mx = 0;
int len = (int)st.size();
int maxn = 0;
for (int i = 1; i < len; ++i) {
if (i < mx) {
p[i] = min(p[2 * id - i], mx - i);
} else {
p[i] = 1;
}
while (st[i - p[i]] == st[i + p[i]]) {
p[i]++;
}
if (mx < i + p[i]) {
mx = i + p[i];
id = i;
}
maxn = max(maxn, p[i] - 1);
}
return maxn;
}
int main() {
string st; cin >> st;
st = init (st);
printf("%d\n", manacher(st, p));
return 0;
}
2.判断有多少个子串是回文串
首先我们肯定能用menacher求回文子串,当然也可以用dp求解(dp的复杂度是O(n^2))
3.最长回文子序列
首先我们来看最长回文子序列
我们定义dp[i][j]代表区间[i,j]内的最长回文子序列的长度
所以我们得到转移方程dp[i][j] = (st[i] == st[j] ? dp[i + 1][j - 1] + 2 : max(dp[i][j - 1], dp[i + 1][j]))
还有另外一种方法来求,我们可以再存一个串,这个串是原串的反转,此时我们可以求两个串的最长公共子序列来求的最长回文子序列长度,通过回溯还可以求出其中的一个最长回文子序列
题目换个说法,求一个字符串最少插入/删除多少个字符可以使得字符串回文
4.回文子序列个数
和最长回文子序列差不多,我们可以定义dp[i][j]代表区间[i, j]回文子序列个数
转移方程为dp[i][j] = (st[i] == st[j] ? dp[i + 1][j] + dp[i][j - 1] + 1 : dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1])
题目还可以换一个意思,删除某些字符使得剩下的字符串是一个回文串,有多少种删除方法