LeetCode 5. Longest Palindromic Substring

本文介绍了三种不同的算法来寻找给定字符串中的最长回文子串:暴力搜索、动态规划和中心扩展法。同时,还提供了Manacher算法的实现,该算法通过记录已匹配的最右位置和对应的对称中心来提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:Longest Palindromic Substring

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.

暴力解决会出现TLE错误。

    string longestPalindrome(string s) {
        int length=0,l=0,r=0;
        for (int len=s.length();len>=0;--len)
        {
            for (int left=0;left+len<s.length();++left)
            {
                int right=left+len,flag=1;
                for (int k=left;k<=(left+right)/2;k++)
                    if (s[k]!=s[left+right-k])
                    {
                        flag=0;
                        break;
                    }
                if (flag&&right-left+1>length)
                {
                    length=right-left+1;
                    l=left;
                    r=right;
                    break;
                }
            }
            if (length!=0) break;
        }
        return s.substr(l,r-l+1);
    }
};

动态规划,如果是字符串[i,j]是回文字符串,则[i+1,j-1]是回文字符串(至少长度为3),所以将加个二维状态数组p[i,j]解释从i到j是否满足是回文字符串。

class Solution {
public:
    string longestPalindrome(string s) {
    const int length=s.size();  
    int maxlength=0;  
    int start;  
    bool P[length+5][length+5]={false};  
    for(int i=0;i<length;i++)//初始化准备  
    {  
        P[i][i]=true;  
        if(i<length-1&&s.at(i)==s.at(i+1))  
        {  
            P[i][i+1]=true;  
            start=i;  
            maxlength=2;  
        }  
        else if (length==1)
        {
            start=i;  
            maxlength=1;  
        }
    }  
    for(int len=3;len<=length;len++)//子串长度  
        for(int i=0;i<=length-len;i++)//子串起始地址  
        {  
            int j=i+len-1;//子串结束地址  
            if(P[i+1][j-1]&&s.at(i)==s.at(j))  
            {  
                P[i][j]=true;  
                maxlength=len;  
                start=i;  
            }  
        }  
        return s.substr(start,maxlength);  
    }
};


中心对称中心扩展就是把给定的字符串的每一个字母当做中心,向两边扩展(奇数扩展,偶数扩展),这样来找最长的子回文串。算法复杂度为O(N^2)。

class Solution {
public:
    string longestPalindrome(string s) {
    const int length=s.size();  
    int maxlength=0;  
    int start;  
    if (length==1)
    {
        start=0;
        maxlength=1;
    }
    else
    {
    start=0;  
    maxlength=1;
    for(int i=0;i<length;i++)//长度为奇数  
    {  
        int j=i-1,k=i+1;  
        while(j>=0&&k<length&&s.at(j)==s.at(k))  
        {  
            if(k-j+1>maxlength)  
            {  
                maxlength=k-j+1;  
                start=j;  
            }  
            j--;  
            k++;  
        }  
    }  
    for(int i=0;i<length;i++)//长度为偶数  
    {  
        int j=i,k=i+1;  
        while(j>=0&&k<length&&s.at(j)==s.at(k))  
        {  
            if(k-j+1>maxlength)  
            {  
                maxlength=k-j+1;  
                start=j;  
            }  
            j--;  
            k++;  
        }  
    }  
    }
    if(maxlength>0)  
        return s.substr(start,maxlength);  
    return NULL;
    }
};


manacher算法通过记录已匹配的最右位置和对应的对称中心来跳过一些没用的比较。

class Solution {
public:
    string longestPalindrome(string s) {
    char tmp[2*s.length()+3]={0};
    int p[2*s.length()+3]={0};
    int id=0,maxlen=0,l=0,len=s.length();//id和maxlen为最长的回文串的中心和中心到最右边长度。
    for (int i=len-1;i>=0;i--)//因为基于中心对称,所以要转成奇数个,添加个#
    {
        tmp[2*i+2]=s[i];
        tmp[2*i+1]='#';
    }
    tmp[0]='*';//防止比较越界
    tmp[2*len+1]='#';
    tmp[2*len+2]='$';
    for (int i=2;i<=2*len;i++)
    {
         //三种情况的总结,i-k在里面,外面,和边界重合。
        if (id+p[id]>i) 
           p[i]=min(p[2*id-i],p[id]-(i-id));
        else
           p[i]=1;
        while (tmp[i-p[i]]==tmp[i+p[i]]) ++p[i];
        if (id+p[id]<i+p[i]) id=i;
        if (maxlen<p[i]) 
        {
            maxlen=p[i];
            if (maxlen==2)
               l=0;
            else
               l=(i-maxlen+2)/2-1;
        }
    }
    string res="";
    for (int i=0,j=l;i<maxlen-1;i++,j++)
    {
       res+=s[j];
    }
    return res;
    }
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值