解题历程
原本想用kmp/哈希映射来写,但是只是大致学习了思想,并没有用这两种方法去写过题目,遂看大家题解(…不可取),发现大家都是用动态规划dp来做的.我惊。
我真的好不会写dp,我枯了。今天晚上把dp对应书上内容看一遍。
三种解法
1.暴力 O(n^3)
2.动态规划dp O(n^2)
3.哈希hash O(nlogn)
动态规划Dp
dp[i][j]表示从i到j是否为回文串
状态转移方程dp[i][j] =
1.dp[i+1][j-1],(S[i]==S[j])
2.0,S[i] != S[j]
初始边界:dp[i][i] = 1, dp[i][i+1] = 1(S[i] == S[i+1])
若直接i,j二重循环从小到大遍历,则dp[0][4]需要从dp[1][3]转移而来,而dp[1][3]此时未遍历过,且无论对i和j的枚举顺序如何调整,都无法调和这个矛盾,故寻找新的枚举方法。
注意到边界表示长度为1和2的子串,且每次转移时都对字符子串的长度-1,故考虑按子串长度和子串的初始位置进行枚举。
代码
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<string>
#include <map>
#define LL long long
using namespace std;
const int maxn = 1010;
int dp[maxn][maxn];
int main(){
string str;
getline(cin, str);
int len = str.size();
int ans = 1;
for(int i = 0; i < len; i++){
dp[i][i] = 1;
if(str[i] == str[i+1]){
dp[i][i+1] = 1;
ans = 2;
}
}
for(int L = 3; L <= len; L++){
for(int i = 0; i + L -1 < len; i++){
int j = i + L -1;//子串的右端点
if(str[i] == str[j] && dp[i+1][j-1]){
dp[i][j] = 1;
ans = L;
}
}
}
printf("%d\n", ans);
return 0;
}