最长回文子串

http://blog.csdn.net/kangroger/article/details/37742639

1、暴力法

最容易想到的就是暴力破解,求出每一个子串,之后判断是不是回文,找到最长的那个。

求每一个子串时间复杂度O(N^2),判断子串是不是回文O(N),两者是相乘关系,所以时间复杂度为O(N^3)。

int FindLongestPalindrome1(string s)
{
int maxLen = 0;
for(int i = 0; i < s.size(); i++)
{
for(int j = i; j < s.size(); j++)
{
string substr = s.substr(i, j-i+1);
int m = 0, n = substr.size()-1;
while(m <= n)
{
if(substr[m] != substr[n])
break;
else
{
m++;
n--;
}
}
if(m > n)
{
if(substr.size() > maxLen)
maxLen = substr.size();
}
}
}
return maxLen;
}

2、动态规划

回文字符串的子串也是回文,比如P[i,j](表示以i开始以j结束的子串)是回文字符串,那么P[i+1,j-1]也是回文字符串。这样最长回文子串就能分解成一系列子问题了。这样需要额外的空间O(N^2),算法复杂度也是O(N^2)。

首先定义状态方程和转移方程:

P[i,j]=0表示子串[i,j]不是回文串。P[i,j]=1表示子串[i,j]是回文串。

则 P[i,j]    = P[i+1,j-1],  if(s[i]==s[j])

    = 0 ,            if(s[i]!=s[j])

int FindLongestPalindrome2(string s)
{
int maxLen = 0;
int len = s.size();
bool **isPalindrome = new bool *[len];
for(int i = 0; i < len; i++)
isPalindrome[i] = new bool[len]();

for(int i = 0; i < len; i++)
{
isPalindrome[i][i] = true;
if(i<len-1 && isPalindrome[i]==isPalindrome[i+1])
{
isPalindrome[i][i+1] = true;
maxLen = 2;
}
}

for(int l = 3; l < len; l++)
{
for(int i = 0; i <= len - l; i++)
{
int j = l+i-1;
if(s[i] == s[j] && isPalindrome[i+1][j-1])
{
isPalindrome[i][j] = true;
maxLen = l;
}
else
isPalindrome[i][j] = 0;
}
}
return maxLen;
}

3、中心扩展

中心扩展就是把给定的字符串的每一个字母当做中心,向两边扩展,这样来找最长的子回文串。算法复杂度为O(N^2)。
但是要考虑两种情况:
1、像aba,这样长度为奇数。
2、想abba,这样长度为偶数。

int ExpandAroundCenter(string s, int c1, int c2)
{
int len = s.size();
int begin = c1, end = c2;
while(begin>=0 && end<=len-1 && s[begin]==s[end])
{
begin--;
end++;
}
return (end-begin-1);  //end-begin+1-2
}


int FindLongestPalindrome3(string s)
{
int len = s.size();
int maxLen = 0;


for(int i = 0; i < len-1; i++)
{
int len1 = ExpandAroundCenter(s, i, i);    //回文长度为奇数,aba
int len2 = ExpandAroundCenter(s, i, i+1);  //回文长度为偶数,abba
int len = (len1 > len2)? len1:len2;
if(len > maxLen)
maxLen = len;
}
return maxLen;
}

4、Manacher法

Manacher法只能解决例如aba这样长度为奇数的回文串,对于abba这样的不能解决,于是就在里面添加特殊字符。我是添加了“#”,使abba变为#a#b#b#a#。这个算法就是利用已有回文串的对称性来计算的,具体算法复杂度为O(N)。
具体算法见leetcode: http://articles.leetcode.com/2011/11/longest-palindromic-substring-part-ii.html

int FindLongestPalindrome4(string s)
{
string t;
for(int i = 0; i < s.size(); i++)
t += "#" + s.substr(i,1);
t += "#";
int len = t.size();
int *num = new int[len]();
int c = 0, r = 0;


for(int i = 0; i < len; i++)
{
int i_mirror = 2*c - i;  //c-(i-c)
num[i] = (r > i)? (min(num[i_mirror], r-i)):0;
while(i+num[i]+1 <= len-1 && i-num[i]-1 >=0 && t[i+num[i]+1] == t[i-num[i]-1])
num[i]++;
if(i+num[i] > r)
{
r = i+num[i];
c = i;
}
}
int maxLen = 0;
for(int i = 0; i < len; i++)
{
if(num[i] > maxLen)
maxLen = num[i];
}
delete []num;
return maxLen;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值