NYOJ-37:回文字符串

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;
}        

猜你喜欢

转载自blog.csdn.net/wingrez/article/details/81836531