回文串就好像aba,abba等,顺着读和反正读相同的字符串,那么如何在一个字符串中找到存在的最大回文串呢?
1.最简单暴力的办法,就是枚举字符串的每个子串,一一求解是否为回文串,最后得到最大的回文串长度。
void circle()
{
char str[50];
while(scanf("%s", str) != EOF)
{
int ans = 1;
for(int i = 0; str[i]; i++)
for(int j = i+1; str[j]; j++)
{
int flag = 0;
int left = i;
int right = j;
while(left < right)
{
if(str[left] != str[right])
{
flag = 1;
break;
}
left++;
right--;
}
if(flag == 0 && (j - i + 1) > ans)
ans = j - i + 1;
}
printf("%d\n", ans);
}
}
这种方法用了一个三重循环,复杂度比较高,所以不推荐。
2.我们先考虑回文串长度为奇数的情况下,aba,ababa,前后都是关于中间的字母对称的,所以,我们可以根据中间的字母,分别求解以这个字母为中心的最长回文串。
可是,当回文串长度为偶数的时候,以上方法就显得不使用了,例如,abba,这里引入manchester方法,在每个字符中间插入一个‘#’,如此就将所有长度为偶数的回文串也变为奇数了。
void circle2()
{
char s[50];
char str[100];
str[0] = '$';
str[1] = '#';
while(scanf("%s", s) != EOF)
{
int n = 2;
for(int i = 0; s[i]; i++)
{
str[n++] = s[i];
str[n++] = '#';
}
str[n] = '\0';
printf("%s\n", str);
int ans = 1;
for(int i = 1; str[i]; i++)
{
int temp;
if(str[i] == '#')
temp = 0;
else
temp = 1;
int left = i-1, right = i+1;
while(str[left] == str[right])
{
if(str[left] != '#')
temp += 2;
left--;
right++;
}
if (ans < temp)
{
ans = temp;
}
}
printf("%d\n", ans);
}
}
这种方法相比暴力法有了很大的提高,但如果字符串是aaaaaaa的时候,时间复杂度还是比较高,有没有更好的办法呢,那就是第三种方法了。
3.首先,我们知道对于偶数长度的回文串,abba,acbbca。中间两个字符一定是相同的,也必定构成回文串,并且,不论中间重复的字符个数是偶数还是奇数,都必定构成回文串,aaa,aaaa,于是就有了第三种方法,如果相邻字符相同,则直接将相同的字符连在一起当作一个字符考虑。例如abba,将bb当作S1,然后再计算,abbba,将bbb当作S2,然后计算,当遇到方法二中的最坏情况,即aaaaaaaa时,直接当作S3。
void circle3()
{
char s[100];
s[0] = '$';
while(scanf("%s", s+1) != EOF)
{
int ans = 1;
for(int i = 1; s[i]; i++)
{
int l, r, t;
l = i;
r = i;
while(s[l] == s[r+1])r++;//处理回文串为偶数的情况
i = r;
while(s[l-1] == s[r+1])
{
l--;
r++;
}
if((t = r-l+1) > ans)
ans = t;
}
printf("%d\n", ans);
}
}