回文字符串 (动态规划,最长公共子序列)

回文字符串

时间限制: 3000 ms | 内存限制: 65535 KB
难度: 4
描述
所谓回文字符串,就是一个字符串,从左到右读和从右到左读是完全一样的,比如"aba"。当然,我们给你的问题不会再简单到判断一个字符串是不是回文字符串。现在要求你,给你一个字符串,可在任意位置添加字符,最少再添加几个字符,可以使这个字符串成为回文字符串。
输入
第一行给出整数N(0<N<100)
接下来的N行,每行一个字符串,每个字符串长度不超过1000.
输出
每行输出所需添加的最少字符数
样例输入
1
Ab3bd
样例输出
2
刚开始看到这道题,看了一会没看出头绪,然后看人家说是要用动态规划里面的最长公共子序列,可是还是想不出为什么。后来同学同学问我这道题,就仔细的想了想。结果发现还真是。
思路:题目中是要求将字符串补成回文串时最少补充的字符。那么我们可以这样想,我们先有一个回文串,然后故意去掉几个。。。就成了题目中的测试案例。
      然后呢,假设去掉的那些字符我们保留为空格,我们想,既然之前是回文的,当我们反转过来背去掉剩下的,然后去掉空格,必然会有些字符还是匹配的,这部分匹配的就是不用动的部分,一个字符串当作模式串,一个当作匹配串,从头到尾匹配,总有一种情况下匹配的字符达到最大,这便是我们把他们变回回文串时不用改动的最大数值,然后根据题意,只要我们拿字符串的总长度减去这个数,便是需要改动的最少个数。也就转化成了求最长公共子序列问题。
 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
 
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
char *reverse( char a[])
{
	char *b=new char[1005];
	int t=strlen(a);
	int i,j;
	for(i=t-1,j=0;i>=0;j++,i--){
		b[j]=a[i];
	}
	return b;
}
int dp[1000][1000];
int main()
{
	int n;
	cin>>n;
	while(n--)
	{
        char a[1005];
        cin>>a;
        int str = strlen(a);
        string b=reverse(a);
        //cout<<b<<endl;
        for(int i =0;i <= str;i ++){
        	for(int j =0 ;j <= str; j++){
        		if(i == 0||j == 0) dp[i][j]=0;
        		else if(b[i-1] == a[j-1]) dp[i][j]=dp[i-1][j-1]+1;
        		else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
        	}
        }
        
        /*for(int i = 0; i <= str; i ++){
        	for(int j = 0;j <= str; j++){
        		cout<<dp[i][j]<<" ";
        	}
        	cout<<endl;
        }*/
        cout<<str-dp[str][str]<<endl;
	}
	return 0;
} 
对案例:asdfgg 进行的测试。

看下图,理解最长公共子序列
案例是:ACDDEB和ADC

 
   
 
   
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值