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

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


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

1     回文长度为1

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


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

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


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

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


 
#include 
#include 
#include 
#include 
#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
#include
#include
#include
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=0&&i+jmax)
				{
					max=j*2+1;
					x=p[i-j];
					y=p[i+j];
				}
			}
			for(int j=0;i-j>=0&&i+j+1max)
				{
					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<




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


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




你可能感兴趣的:(NYOJ,XJB,算法)