NYOJ-37:回文字符串
来源:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=37
标签:动态规划,回文串,最长公共子序列
参考资料:
相似题目:
题目
所谓回文字符串,就是一个字符串,从左到右读和从右到左读是完全一样的,比如”aba”。当然,我们给你的问题不会再简单到判断一个字符串是不是回文字符串。现在要求你,给你一个字符串,可在任意位置添加字符,最少再添加几个字符,可以使这个字符串成为回文字符串。
输入
第一行给出整数N(0 < N < 100)
接下来的N行,每行一个字符串,每个字符串长度不超过1000.
输出
每行输出所需添加的最少字符数
输入样例
1
Ab3bd
输出样例
2
解题思路(个人理解)
回文串就是顺序读和逆序读是一样的,现在有一个字符串s1,我们的目的是把s1变成一个回文串。做法是把s1逆序后得到s2(图1),如果s1=s2,那么s1就是一个回文串。
该怎么做呢?我们往s1、s2中尽量少地添加一些字符使s1=s2,也就是让两者的最长公共子序列就是它们本身。注意到,s1和s2中已经存在一些公共子序列(图2),所以最少的字符添加数等于s1字符串长度减去这些公共子序列的长度。见参考代码1。
图1
![]()
图2
![]()
图3
参考代码1
#include<stdio.h>
#include<string.h>
#define MAXN 1005
char s1[MAXN];
char s2[MAXN];
int L[MAXN][MAXN];//L[i][j]:str1[0~i-1]和str2[0~j-1]的LCS长度
int main(){
int n;
scanf("%d",&n);
while(n--){
scanf("%s",s1);
int len=strlen(s1);
for(int i=0;i<len;i++){
s2[i]=s1[len-i-1];
}
s2[len]='\0';
//求LCS长度
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
if(s1[i]==s2[j])
L[i+1][j+1]=L[i][j]+1;
else L[i+1][j+1]= L[i][j+1]>L[i+1][j]? L[i][j+1]: L[i+1][j];
}
}
printf("%d\n",len-L[len][len]);
}
return 0;
}
参考代码2
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 1005
using namespace std;
char s[MAXN];
int dp[MAXN][MAXN];//dp[i][j]:从i到j构成回文串最少添加的字符数
int main(){
int n;
scanf("%d",&n);
while(n--){
scanf("%s",s);
int len=strlen(s);
memset(dp,0,sizeof(dp));
for(int l=1;l<len;l++){
for(int i=0,j=l; j<len; i++,j++){
if(s[i]==s[j])
dp[i][j]=dp[i+1][j-1];
else
dp[i][j]=min(dp[i+1][j], dp[i][j-1]) +1;
}
}
printf("%d\n",dp[0][len-1]);
}
return 0;
}