NSWOJ 1228 && NYOJ 132 最长回文子串

来源:互联网 发布:手机u盘数据恢复 编辑:程序博客网 时间:2024/06/05 04:41

给你一个字符串 让你求最长回文子串 、


个人认为 如果你想尝试用一般的方法 写这道题 需要注意的点有 

1     回文长度为1

2    回文分为奇数长度和偶数长度两种 如果你没用马拉车算法  这个地方很容易出bug


这道题讨厌的地方在忽略标点   需要你开另一个数组存储真正求回文的字符串  

刚开始我写的非常繁琐 因为要记录字符的对应位置什么的 开了很多变量来储存这些信息


第一次a这道题的代码 是枚举每一个点  然后从这个点找出围绕改点的最长回文  维护一个最大值  大概这样 的东西  

由于 用了很多函数  或者说 自己代码风格比较差还是什么原因  写的很冗长但是 时间是 4ms


 #include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#define debug() printf("GG~~\n")using namespace std;const int N = 5005;char str[N];int maxn , L , R, length;inline bool check(int x){    if(x < 0 || x >= length)return false;    else return true;}int FindLeft(int x,int p)//第二个参数的意思是  在寻找点的时候是否包括x点 {    int deviation = p;    if(x - deviation < 0)return -1;    while (check(x - deviation)) {        if(isalpha(str[x - deviation]))return x - deviation;        else deviation ++;        if(x - deviation < 0)return -1;    }    return -1;}int FindRight(int x,int p){    int deviation = p;    if(x + deviation >= length)return -1;    while (check(x + deviation)) {        if(isalpha(str[x + deviation])) return x + deviation;        else deviation ++;        if(x + deviation > length) return -1;    }    return -1;}bool judge(char a,char b){    if(a >= 'A' && a <= 'Z')a = a - 'A' + 'a';    if(b >= 'A' && b <= 'Z')b = b - 'A' + 'a';    if(a == b)return true;    else return false;}void lps(int pos){    //奇数时  双向发散    int l = FindLeft(pos, 1), r = FindRight(pos, 1);    int res = 1;    while (true) {//奇数  双向发散       // if(r == -1)debug();        if(l == -1 || r == -1)break;        if(judge(str[l], str[r])) {            res += 2;            if(res > maxn) {                maxn = res;L = l,R = r;            }        }else break;        l = FindLeft(l, 1);        r = FindRight(r , 1);    }    res = 0;    l = FindLeft(pos - 1, 0);    r = FindRight(pos, 0);    while (true) { //偶数 左侧开始双向发散        if(l == -1 || r == -1)break;        if(judge(str[l], str[r])) {            res += 2;            if(res > maxn) {                maxn = res;                L = l,R = r;            }        } else break;        l = FindLeft(l, 1);        r = FindRight(r, 1);    }    res = 0;    l = FindLeft(pos, 0);    r = FindRight(pos + 1, 0);    while (true) {     //   printf("l == %d  r == %d\n",l,r);        if(l == -1 || r == -1)break;        if(judge(str[l], str[r])) {            res += 2;            if(res > maxn) {                maxn = res;                L = l, R = r;            }        } else break;        l = FindLeft(l, 1);        r = FindRight(r, 1);    }}int main(){    int t;    scanf("%d",&t);    getchar();    while ( t -- ) {       gets(str);        maxn = 0;        length = strlen(str);        for (int i = 0; i < length ; i ++)            lps(i);        if(maxn == 0) {            for (int i = 0; i < length; i ++) {                if(isalpha(str[i])) {                    L = R = i;break;                }            }        }       // printf("%d \n",maxn);        for (int i = L; i <= R; i ++)            printf("%c",str[i]);        printf("\n");    }}        

如果你觉得上一份代码 冗长不想看  这里有一份 来自NYOJ的代码
思路和我上面的这个很像  但是写的比我更短更清晰更睿智
有些人总是能写得很简洁 很高效

 #include<iostream>#include<string.h>#include<ctype.h>#include<cstdio>using namespace std;const int MAX=5100;char Yuan[MAX],s[MAX];int p[MAX];int main(){/*freopen("1.txt","r",stdin);freopen("2.txt","w",stdout);*/int n;cin>>n;getchar();while(n--){int max=0,x,y,m=0;gets(Yuan);int n=strlen(Yuan);for(int i=0;i<n;i++){if(isalpha(Yuan[i])){p[m]=i;s[m++]=toupper(Yuan[i]);}}for(int i=0;i<m;i++){for(int j=0;i-j>=0&&i+j<m;j++){if(s[i-j]!=s[i+j])break;if(j*2+1>max){max=j*2+1;x=p[i-j];y=p[i+j];}}for(int j=0;i-j>=0&&i+j+1<m;j++){if(s[i-j]!=s[i+j+1])break;if(j*2+2>max){max=j*2+2;x=p[i-j];y=p[i+j+1];}}}for(int k=x;k<=y;k++){printf("%c",Yuan[k]);}cout<<endl;}}        




第二种方法
写法比较简单  思路是这样的  暴力枚举所有区间  在暴力匹配区间是不是回文区间  维护最大值 即可 
这种方法 复杂度 n^3 浪费时间在检测一个区间是不是回文区间上  
因为这种方法没有任何地方比上面给的方法好  就不写了 


当然你可以用马拉车算法优化判断回文的过程   这样就比上面的代码快了 但是由于上一份代码  0ms  就没有去学马拉车写法的动力了
留着以后补上吧还是 




原创粉丝点击