1.直接比较法。
假设当前位置为回文的中点,比较两侧的相等字符个数。
eg:s1=”123abccba45”,首先变为”1#2#3#a#b#c#c#b#a#4#5#”
这样做的原因是使算法更简练:假设字符c是回文中点,但有两种情况,回文是奇数长度和偶数长度。
将字符串扩展后,偶数长回文都是在#处分析。
int huiwen(char* input,int length,char* output)
{
if((input==0)||(length<1))
exit(1);
char* new_input=new char[2*length];
for(int i=0;i<length;i++)
{
new_input[2*i]=input[i];
new_input[2*i+1]='#';
}
int start=0;
int size=1;
int index=1;
int new_length=2*length;
for(;index<new_length;index++)
{
int n=1;
while((index-n)>=0 && (index+n)<new_length &&
new_input[index-n]==new_input[index+n])
n++;
if((n-1)>size)
{
if(index%2==0)
start=index/2-(n-1)/2;
else
start=(index-n+2)/2;
size=n-1;
}
}
delete[] new_input;
memmove(output,input+start,size);
output[size]=0;
return size;
}
2动态规划
这里动态规划的思路是 dp[i][j] 表示的是 从i 到 j 的字串,是否是回文串。
则根据回文的规则我们可以知道:
如果s[i] == s[j] 那么是否是回文决定于 dp[i+1][ j - 1]
当 s[i] != s[j] 的时候, dp[i][j] 直接就是 false。
动态规划的进行是按照字符串的长度从1 到 n推进的。
int huiwen2(char* pstr,int length,char* pout)
{
if(!pstr || length<1 || !pout)
abort();
bool** bre=new bool*[length];
for(int m=0;m<length;m++)
bre[m]=new bool[length];
for(int i=0;i<length;i++)
{
bre[i][i]=true;
}
int max=1;
int max_index=0;
for(int n=2;n<=length;n++)
{
for(int j=0;j<=(length-n);j++)
{
if((pstr[j]==pstr[j+n-1]) && (bre[j+1][(n==2)?(j+1):(j+n-2)]))
{
bre[j][j+n-1]=true;
max=n;
max_index=j;
}
else
bre[j][j+n-1]=false;
}
}
for(int m=0;m<length;m++)
delete[] bre[m];
delete[] bre;
for(int k=0;k<max;k++)
pout[k]=pstr[max_index+k];
pout[max]='\0';
return max;
}
3KMP算法:
对于串S, 假设它的 Reverse是 S', 那么S的最长回文串是 S 和 S' 的最长公共字串。
例如 S = abcddca, S' = acddcba, S和S'的最长公共字串是 cddc 也是S的最长回文字串。
如果S‘是 模式串,我们可以对S’的所有后缀枚举(S0, S1, S2, Sn) 然后用每个后缀和S匹配,寻找最长的匹配前缀。
例如当前枚举是 S0 = acddcba 最长匹配前缀是 a
S1 = cddcba 最长匹配前缀是 cddc
S2 = ddcba 最长匹配前缀是 ddc