判断是否为回文串
回文字符串是一种正反颠倒之后还与原来相同的字符串,所以当判定一个字符串是否是回文字符串时,我们可以这样判断:
(1)当字符串长度为奇数时,找到处于中间位置的下标,比较与它相同远的两个字符是否相同即可
(2)长度为偶数时,找到最中间的两个,然后与奇数相同的处理情况即可。
#include<iostream>
#include<string>
using namespace std;
string s;
int solve1(int x)
{
int l=x-1;
int r=x+1;
while(l>=0&&r<(int)s.size())
{
if(s[l]==s[r])
{
l--;
r++;
}
else
return 0;
}
return 1;
}
int solve2(int x)
{
int l=x-1;
int r=x;
while(l>=0&&r<(int)s.size())
{
if(s[l]==s[r])
{
l--;
r++;
}
else
{
return 0;
}
}
return 1;
}
int main()
{
cin>>s;
int len=s.size();
int f;
if(len%2) //长度为奇数时
f=solve1(len/2);
else //长度为偶数时
f=solve2(len/2);
if(f)
cout<<"yes"<<endl;
else
cout<<"no"<<endl;
return 0;
}
最长回文子串
输入一个字符串Str,输出Str里最长回文子串的长度。输入一个字符串Str,输出Str里最长回文子串的长度。
回文串:指aba、abba、cccbccc、aaaa这种左右对称的字符串。
串的子串:一个串的子串指此(字符)串中连续的一部分字符构成的子(字符)串
例如 abc 这个串的子串:空串、a、b、c、ab、bc、abc.
输入Str(Str的长度 <= 1000)
最长回文子串
因为数据范围只有1000,所有可以采用暴力的做法,假设字符串中的每一个字符都处于中间的位置,在分为处于奇数和偶数长度的回文字符串中两种情况,暴力枚举即可
#include<iostream>
#include<string>
using namespace std;
const int N=1e5+10;
string s;
int solve1(int x) //奇数
{
int len=1;
int l=x-1;
int r=x+1;
while(l>=0&&r<s.size())
{
if(s[l]==s[r])
{
l--;
r++;
len+=2;
}
else
break;
}
return len;
}
int solve2(int x) //偶数
{ int len=0;
int l=x;
int r=x+1;
while(l>=0&&r<s.size())
{
if(s[l]==s[r])
{
l--;
r++;
len+=2;
}
else
break;
}
return len;
}
int main()
{
cin>>s;
int ans=0;
for(int i=0;i<s.size();i++)
{
ans=max(ans,solve1(i));
ans=max(ans,solve2(i));
}
cout<<ans<<endl; //最长回文字符串的长度
return 0;
}
但当数据范围过大时,这种做法会超时。
例如(Str的长度 <= 100000)
这时,就可以使用一种叫manacher的算法,他能以O(n)的复杂度找出最长回文子串。
首先对于奇回文串和偶回文串,可以这样处理:
将abacbb变为#a#b#a#c#b#b#
这样偶回文子串就变成了以#为中心的奇回文子串,原本的子串长度就变成了现在子串长度半径-1。
然后还有一个知识,回文串中如果左半边有一个回文子串,那在右半边相对的位置的子串也是一个回文子串。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#include <set>
#include <ctime>
#include <utility>
#include <unordered_map>
#define MM(x, y) memset(x, y, sizeof(x))
#define lowbit(x) ((x) & (-x))
#define ll long long
#define INF 0x3f3f3f3f
#define bug puts("bugbugbug");
//priority_queue<int,vector<int>,greater<int> >c;
//priority_queue<int>c;
using namespace std;
const int N=2e5+10;
char a[N],s[N];
int len[N];
int n;
int ans=0;
void init() //将字符串转换为#a#a#的形式
{
s[0]=s[1]='#';
for(int i=0;i<n;i++)
{
s[i*2+2]=a[i];
s[i*2+3]='#';
}
n=n*2+2;
s[n]='!'; //末尾加一个不常用的字符,防止越界
}
void manacher()
{
int mr=0,mid; //mr 记录的时已知的回文子串的右边界能到达的最远位置,mid为此时回文子串的中心位置
for(int i=1;i<n;i++) //遍历每一个以s[i]为中心的子串长度
{
if(i<mr) //如果i<mr,那么以i为中心的子串长度有过重复计算,找到关于mid对称的左边位置的回文子串长度,在与mr的距离取最小值即可
len[i]=min(len[2*mid-i],mr-i);
else
len[i]=1;
while(s[i-len[i]]==s[i+len[i]])
len[i]++;
if(i+len[i]>mr) //更新mr 和mid
{
mr=i+len[i];
mid=i;
}
ans=max(ans,len[i]);
}
}
int main()
{
ans=0;
MM(len,0);
scanf("%s",a);
n=strlen(a);
init();
manacher();
cout<<ans-1<<endl;
return 0;
}