题目大意:给你一个字符串(区分大小写),要求你添加最少的字符使其变成回文串,问最少添加几个字符。
思路:此题的答案=原字符串长度-原字符串与前后颠倒后的字符串的最长公共子串长度(LCS)。
求LCS用DP。
此题字符串最长能达5000,数组需要开5000*5000*int,会“炸”(MLE)。解决办法:①用short;②用滚动数组。
下面是两者的对比(上面是方法①,下面是方法②):
由此可见,方法②完胜方法①(尤其是内存,相差49028K!)。(不会滚动数组的使用方法①也是个选择)
C++ Code:
方法①:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; char a[5005],b[5005]; int dp[2][5005]; int l; int main(){ while(scanf("%d",&l)!=EOF){ memset(a,0,sizeof(a)); a[0]='^'; scanf("%s",a+1); strcpy(b,a); memset(dp,0,sizeof(dp)); reverse(b+1,b+l+1); int Max=0; for(int i=1;i<=l;i++) for(int j=1;j<=l;j++){ if(a[i]==b[j])dp[i%2][j]=dp[(i-1)%2][j-1]+1; else dp[i%2][j]=max(dp[i%2][j-1],dp[(i-1)%2][j]); if(Max<dp[i%2][j])Max=dp[i%2][j]; } printf("%d ",l-Max); } return 0; }
方法②:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; char a[5005],b[5005]; short dp[5005][5005]; int l; int main(){ while(scanf("%d",&l)!=EOF){ memset(a,0,sizeof(a)); a[0]='^'; scanf("%s",a+1); strcpy(b,a); memset(dp,0,sizeof(dp)); reverse(b+1,b+l+1); for(int i=1;i<=l;i++) for(int j=1;j<=l;j++){ if(a[i]==b[j])dp[i][j]=dp[i-1][j-1]+1; else dp[i][j]=max(dp[i][j-1],dp[i-1][j]); } printf("%d ",l-dp[l][l]); } return 0; }