最长回文子串

来源:互联网 发布:怎么ping网络通不通 编辑:程序博客网 时间:2024/05/02 01:50

回文串:如果一个字符串正着读和反着读是一样的,那么它就是一个回文串。例如,a,aba,abba,aaaa等都是回文串。
最长回文子串问题是指,给定一个字符串,求出这个字符串中最长的连续的回文子串。
最长回文子串问题容易与最长回文序列问题混淆,最长回文字串是在给定字符串中连续的回文子串,而最长回文序列问题中可以不连续。例如,给定一个字符串abcbdda,这个字符串的最长回文子串是abc或bcb,而最长回文子序列为abba或adda。

最长回文子串解法一:暴力搜索
对于最长回文子串问题,最容易想到的方法也是最简单粗暴的解法就是,遍历字符串所有子串,并确定每一个子串是否为回文串。一个字符串中,它的字串的数量为O(n^2),遍历每个子串需要O(n)的时间,因此,这个解法的时间复杂度为O(n^3)

最长回文字符串解法二:动态规划
可能有很多人像我一样会想到,这是一个动态规划问题。判断动态规划问题的两个显著条件就是:一.原始问题具有最优子结构。二.子问题的解有重叠
首先我们可以将这个问题分解为子问题,即将一个字符串s分解为O(n^2)个子串,然后判断每个子串是否为一个回文串,并找到最长的回文子串。
假如s[i,j]是一个回文串(i-j>=2),那么s[i+1,j-1]一定也是一个回文串,那么对于子问题:判断s[i,j] (i-j>=2)是否是一个回文串,那么我们首先可以判断s[i+1,j-1]是否为一个回文串,1.如果s[i+1,j-1] 是回文串,那么我们接下来可以根据s[i]是否等于s[j]来判断s[i,j]是否为回文串,2.如果s[i+1,j-1]不是回文串,那么s[i,j]一定也不是回文串。以record[i,j]记录s[i,j]是否为回文串,则有:

record[i,j]=true,i=jtrue,j=i+1 and s[i]=s[j]true,s[i]=s[j] and record[i+1,j1]=truefalse,otherwise

string longestPalindrome(string s) {        int length=s.length();        vector<vector<bool>> record(length,vector<bool>(length,false));        for(int i=0;i<length;++i)            record[i][i]=true;        for(int l=1;l<length;++l){ //先解决字符串长度为l+1的最优子问题            for(int i=0;i+l<length;++i){ //i是子字符串起始位置                if(s[i]==s[i+l]){                    if(l==1)                        record[i][i+l]=true;                    else if(record[i+1][i+l-1]==true)                        record[i][i+l]=true;                }            }        }        int start=0;        int end=0;        int maxLen=0;        for(int i=0;i<length;++i)            for(int j=i;j<length;++j){                if(record[i][j]==true && j-i+1>maxLen){                    start=i;                    end=j;                    maxLen=j-i+1;                }            }        return s.substr(start,end-start+1);    }

动态规划算法的时间复杂度为O(n^2),空间复杂度为O(n^2)。
那么有没有复杂度更低的算法呢?

最长回文子串解法三:Manacher 算法
Manacher算法讲解的非常详细,时间复杂度为O(n)。
程序如下:

 string longestPalindrome(string s){        //Manacher法        int length=s.length();        string pad_s;        pad_s.resize(2*length+1);        for(int i=length-1;i>=0;--i){            pad_s[2*i+2]='#';            pad_s[2*i+1]=s[i];        }        pad_s[0]='*'; //防止在下面的while循环中出界        vector<int> r(2*length+1,0);        int center=0;        int maxStart=0,maxEnd=0,maxLen=0;        for(int i=1;i<2*length+1;++i){            if(center+r[center]>i)                r[i]=min(r[center]-(i-center),r[center-(i-center)]);            else                 r[i]=1;            while(pad_s[i+r[i]]==pad_s[i-r[i]])                ++r[i];            if(i+r[i]>center+r[center])                center=i;            if(r[i]>maxLen){                maxLen=r[i];                maxStart=i-r[i]+1;                maxEnd=i+r[i]-1;            }        }        string result;        for(int k=maxStart;k<=maxEnd;++k){            if(pad_s[k]!='#')                result.push_back(pad_s[k]);        }        return result;    }
0 0
原创粉丝点击