首先解释题目的意思:
Palindromic Substring是“回文”的意思。
什么是回文呢?它是一种修辞手法。如“凤落梧桐梧落凤”这句话就是用了回文的修辞。
这道题目的意思是让你求一个字符串中的最长回文串,如“ababc”中最长回文串是“aba”.
暴力方法:时间复杂度O(n^2),空间复杂度O(1)(读了leetcode上的一篇文章后发现,还有更暴力的方法,时间复杂度是O(n^3),该方法直接判断源字符串的每个子字符串是不是回文。。本菜突然觉得进步了一点点。)
思路:分别以每个字符为中心,遍历以其为中心的字符串是不是回文,并取最长回文。下面举一个例子
str = abab
以str[0](即第一个a)为中心,最长扩展半径是0(因为它已经是左边界了,以它为中心的字符串长度最大只能是1),最长回文只能是a;
以str[1](即第一个b)为中心,最长扩展半径是1(因为它的左右两边都有字符,但是以它为中心,最多只能扩展1位,因为如果扩展2位,左边就越界了,所以以它为中心的子字符串的最大长度是3),最长回文是aba;
以str[2](即第二个a)为中心,最长扩展半径是1(以它为中心,最多只能扩展1位,因为如果扩展2位,右边就越界了,所以以它为中心的子字符串的最大长度是3),最长回文是bab;
以str[3](即第二个b)为中心,最长扩展半径是0(因为它已经是右边界了,以它为中心的字符串长度最大只能是1),最长回文只能是b;
检测最长回文的思想:首先需要分类,一类是最长回文字符串长度为奇数,另一类是长度为偶数(上面分析的只是最长回文字符串长度为奇数的情况),具体如何检测,情况代码。
代码如下:
char* longestPalindrome(char* s) {
//最直观的方法——用每个点做回文终点,遍历所有可能性,时间复杂度为n^2
//稍微改进的方法——从中间点开始找,记录当前找到的最大回文串长度,
//如s长为5,中点最大回文长3,其它点就不用找了
int index_max, index_current;
int srcLen = 0;
bool oddlen = true;
int maxlen = 0;
while (s[srcLen] != ‘\0’)
{
srcLen++;
}
int srcLen_d1 = srcLen – 1;
int radius_posibal_odd, radius_posibal_even;
int i = 0;
for (index_current = 0; index_current < srcLen; index_current++)
{
int len, substrcount;
radius_posibal_odd = index_current>(srcLen – index_current – 1) ? srcLen – index_current – 1 : index_current;
radius_posibal_even = index_current + 1 > srcLen – 1 – index_current ? srcLen – 1 – index_current : index_current + 1;
if (maxlen < 1 + radius_posibal_odd * 2)
{
//回文串长度为奇数
i = 1;
len = 0;
substrcount = 0;
while (i <= radius_posibal_odd)
{
if (s[index_current – i] == s[index_current + i])
substrcount++;
else
{
len = substrcount * 2 + 1;
if (len > maxlen)
{
maxlen = len;
oddlen = true;
index_max = index_current;
}
break;
}
i++;
}
len = substrcount * 2 + 1;
if (len > maxlen)
{
maxlen = len;
oddlen = true;
index_max = index_current;
}
}
if (maxlen < radius_posibal_even * 2)
{
//回文串长度为偶数
i = 0;
len = 0;
substrcount = 0;
while (i<radius_posibal_even)
{
if (s[index_current – i] == s[index_current + 1 + i])
substrcount++;
else
{
len = substrcount * 2;
if (len>maxlen)
{
maxlen = len;
oddlen = false;
index_max = index_current;
}
break;
}
i++;
}
len = substrcount * 2;
if (len > maxlen)
{
maxlen = len;
oddlen = true;
index_max = index_current;
}
}
}
int index_rs;
if (oddlen)
{
index_rs = index_max – (maxlen – 1) / 2;
}
else
{
index_rs = index_max – (maxlen / 2 – 1);
}
char *rs = (char*)malloc((maxlen + 1)*sizeof(char));
for (i = 0; i < maxlen; i++)
{
rs[i] = s[index_rs + i];
}
rs[i] = ‘\0’;
return rs;
}
动态规划法:时间复杂度O(n^2),空间复杂度O(n^2),空间复杂度可以优化到O(n)
连接如下:http://articles.leetcode.com/2011/11/longest-palindromic-substring-part-i.html
C 0ms解法(其实该方法就是最开始的“暴力方法”的优化,但是给出该方法的人说该方法的时间复杂度是O(n)):
char* longestPalindrome(char* s) {
char *go,*max_start,*left,*right,*re;
int max_length,temp_length;
char *s_end;
s_end = s+strlen(s);
if (strlen(s) == 0) return s;
if (strlen(s) == 1) return s;
for(go = s,max_length = 1;go<s_end;)
{
if (s_end – go <= max_length * sizeof(char) / 2) break;
left = go,right = go;
while(*right==*(right+1)) right++;
go = right + 1;
while(left<s_end && left>s && *(left-1) == *(right+1))
{
right++;
left–;
}
temp_length = (right-left)/sizeof(char) + 1;
if(temp_length > max_length) {
max_start = left;
max_length = temp_length;
}
}
re =(char *) malloc(max_length*sizeof(char)+1);
go = re;
while(max_length)
{
*(go) = *(max_start);
go++;
max_start++;
max_length–;
}
*go = ‘\0’;
return re;
manacher’s 算法:
没搞明白,而且算法速度也没有上面的方法块。。。记录它的原因是因为它需要重新构造一个字符串,目的是为了省去回文串长度为偶数和奇数时算法上的不同。
字符添加方法举例如下:添加前的字符串为abc,添加之后变为#a#b#c#。
具体原理讲解在:
英文原文:http://articles.leetcode.com/2011/11/longest-palindromic-substring-part-ii.html
汉语译文:http://www.cnblogs.com/bitzhuwei/p/Longest-Palindromic-Substring-Part-II.html