最长回文子字符串

给出一个字符串,我们需要找到最长的回文子字符串,回文子字符串有两种,一种是奇数型,如 aba ,一种是偶数形,如 abba ,所谓的回文字符串就是这个字符串正读或者倒度都是相同的。为了统一处理这两种回文字符串,我们将原字符串每隔一个字符,添加一新字符,我们在这里用 来表示,举个例子就是将aba变成 aba ,这样任何的回文字符串都是奇数长。
我们将对变换过后的字符串进行扫描。记录以每个元素为中心的最长回文字符串的半径长度。同时我们记录这个回文字符串最右端的位置和maxid进行比较,如果比它大就将它更新,我们用下图来说明这样做的目的

这里写图片描述
假设当前扫描到第 i 个位置,以它为中心的最长回文字符串的最右端位置为maxid,那么如果下一个扫描到的是位置j,它关于 i 的对称位置为2ij,显然两者的回文长度在maxid内是相等的,所以我们便可以确定以 j 为中心的会问长度半径长度为min{P[2ij],maxidj},其中 P[2ij] 表示的就是以 2ij 位置上的元素为中心的最长回文字符串的半径长度。
这样我们就得到了变换后的字符串的每个元素为中心的最长回文字符串的半径长度。当然包括 ,接下来的事情就是读出最长的回文字符串,因为我们在上步中已经记录了最长回文字符串所对应的位置,这样,我们找到这个位置,设为i,那么在原字符中的最长回文串的最左端的字符为为变换过后的字符串的第 ip+2 位置上的字符,最右端的字符为变换过后的字符串的第 i+p2 的元素。

char *longestPalindrome(char *s)
{
    int len_s=strlen(s);
    char *new_s=malloc(sizeof(char)*(2*len_s+3));
    int *P=malloc(sizeof(int)*(2*len_s+3));
    char *result=malloc(sizeof(char)*(len_s+1));
    new_s[0]='#';
    new_s[2*len_s+2]='$';
    int i;
    int max_len=0;
    int maxid=0;
    int id=0,len_id=0;

    for(i=1;i<=2*len_s+2;i++)
    {
        if(i % 2==1)
            new_s[i]='*';
        else
            new_s[i]=s[(i-2)/2];
    }

    for(i=1;i<2*len_s+2;i++)
    {
        if(i<maxid)
            P[i]=P[2*id-i]>(maxid-i)?(maxid-i):P[2*id-i];
        else
            P[i]=1;
        while(new_s[i-P[i]]==new_s[i+P[i]])
            P[i]++;
        if(i+P[i]>maxid)
        {
            maxid=i+P[i];
            id=i;
        }
        if(P[i]>max_len)
        {
            max_len=P[i];
            len_id=i;
        }
    }
    memcpy(result,s+(len_id-max_len)/2,max_len-1);
    result[max_len-1]='\0';
    return result;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值