最长回文子序列
状态转移
设 d [ i ] [ j ] d[i][j] d[i][j]表示以 i i i为起点以 j j j为终点的区间内的最长回文子序列长度,显然此问题类似于最大公共子序列,那么我们可以得到递推方程:
- 若 s [ i ] = = s [ j ] s[i]==s[j] s[i]==s[j],那么 d [ i ] [ j ] = d [ i + 1 ] [ j − 1 ] + 2 d[i][j] = d[i+1][j-1]+2 d[i][j]=d[i+1][j−1]+2
- 否则 d [ i ] [ j ] = m a x ( d [ i + 1 ] [ j − 1 ] , d [ i ] [ j − 1 ] ) d[i][j] = max(d[i+1][j-1],d[i][j-1]) d[i][j]=max(d[i+1][j−1],d[i][j−1])
代码
不难发现大区间依赖于小区间,那么必须按区间DP的思想更新状态转移方程,可以得到如下三种写法的代码:
int d[1005][1005];
char s[1005];
void solve1() {
int n = strlen(s + 1);
for (int i = 1; i <= n; i++) d[i][i] = 1;
for (int len = 2; len <= n; len++) {
for (int i = 1; i <= n - len + 1; i++) {
int j = i + len - 1;
if (s[i] == s[j])
d[i][j] = d[i + 1][j - 1] + 2;
else
d[i][j] = max(d[i + 1][j], d[i][j - 1]);
}
}
}
void solve2() {
int n = strlen(s + 1);
for (int i = 1; i <= n; i++) d[i][i] = 1;
for (int i = n; i >= 1; i--) {
for (int j = i + 1; j <= n; j++) {
if (s[i] == s[j])
d[i][j] = d[i + 1][j - 1] + 2;
else
d[i][j] = max(d[i + 1][j], d[i][j - 1]);
}
}
}
void solve3() {
int n = strlen(s + 1);
for (int i = 1; i <= n; i++) d[i][i] = 1;
for (int j = 1; j <= n; j++) {
for (int i = 1; i < j; i++) {
if (s[i] == s[j])
d[i][j] = d[i + 1][j - 1] + 2;
else
d[i][j] = max(d[i + 1][j], d[i][j - 1]);
}
}
}
最长回文子串
这里不考虑马拉车算法,只考虑DP
状态转移
和最长回文子序列,如果设 d [ i ] [ j ] d[i][j] d[i][j]表示以 i i i为起点以 j j j为终点的区间内的最长回文子串长度,那么状态转移时,若 s [ i ] = = s [ j ] s[i]==s[j] s[i]==s[j],但是区间内最长子串的起点和终点并不能确定,除非 d [ i + 1 ] [ j − 1 ] d[i+1][j-1] d[i+1][j−1]本身就是最大的回文子串,因此,这里只能用 d [ i ] [ j ] d[i][j] d[i][j]表示区间 [ i , j ] [i,j] [i,j]整体是否为回文子串:
- 若 s [ i ] = = s [ j ] & & d [ i − 1 ] [ j + 1 ] = 1 s[i]==s[j]~~\&\&~~d[i-1][j+1] = 1 s[i]==s[j] && d[i−1][j+1]=1,那么 d [ i ] [ j ] = 1 d[i][j] = 1 d[i][j]=1
- 否则 d [ i ] [ j ] = 0 d[i][j] = 0 d[i][j]=0
代码
只需要每次 d [ i ] [ j ] = = 1 d[i][j]==1 d[i][j]==1时更新答案 a n s ans ans,设置 d [ i + 1 ] [ i ] = 1 d[i+1][i]=1 d[i+1][i]=1是为了特判长度为 2 2 2的情况。
int d[1005][1005];
char s[1005];
int solve1() {
int n = strlen(s + 1), ans = 1;
for (int i = 1; i <= n; i++) d[i][i] = d[i + 1][i] = 1;
for (int len = 2; len <= n; len++) {
for (int i = 1; i <= n - len + 1; i++) {
int j = i + len - 1;
if (s[i] == s[j] && d[i + 1][j - 1]) {
d[i][j] = 1;
ans = max(ans, len);
}
}
}
return ans;
}
int solve2() {
int n = strlen(s + 1), ans = 1;
for (int i = 1; i <= n; i++) d[i][i] = d[i + 1][i] = 1;
for (int i = n; i >= 1; i--) {
for (int j = i + 1; j <= n; j++) {
if (s[i] == s[j] && d[i + 1][j - 1]) {
d[i][j] = 1;
ans = max(ans, j - i + 1);
}
}
}
return ans;
}
int solve3() {
int n = strlen(s + 1), ans = 1;
for (int i = 1; i <= n; i++) d[i][i] = d[i + 1][i] = 1;
for (int j = 1; j <= n; j++) {
for (int i = 1; i < j; i++) {
if (s[i] == s[j] && d[i + 1][j - 1]) {
d[i][j] = 1;
ans = max(ans, j - i + 1);
}
}
}
return ans;
}