欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

字符串--最长回文子串(暴力讲解+Manacher)

程序员文章站 2022-03-21 21:43:44
...

问题描述:给你一个字符串str,若子串s是回文串,则称s为str的回文子串,求s的最大长度

解法一:暴力匹配

              对每一个字符,假定位置为i,匹配判断i+1与i-1位置是否相等,相等ans长度加一,否则停止。

        字符串--最长回文子串(暴力讲解+Manacher)

              对奇数,ans=1;对偶数,ans初始为0.(不知道奇数偶数,两种都要写,最后取较大值)。奇数偶数都要判断,代码很长,复杂度O((2*N+1)*N)=O(N^2).

              比起一般暴力三方快一点。

解法二:Manacher

     严格复杂度O(N)       

     step1:预处理,将奇偶变为奇数。

             对于一个串str长度为n,有n-1个空格,首位有两个,对这些空处理,长度变成2n+1。

 

字符串--最长回文子串(暴力讲解+Manacher)

     可以加str中不存在的东西,比如#。

             step2: 构造数组p[n]

            数组p[i]来记录字符串s[i]最长回文串向左向右扩张p[i]长度的最大值。

         字符串--最长回文子串(暴力讲解+Manacher)

     如图,对应的关系,p[i]-1正好是原字符串最长回文子串的长度。

     如何求p[i]数组?

      求p[i]时,p[1]....p[n]是已知的。

      对任意位置i,可以扩张的范围是i±p[i],这个范围都是回文的。对于k+p[k](k=1,2,.....i-1)有最大值记为mx,有一个id(id的值就是前面mx取得最大值对应的p[k]的k的值),

     i关于id的位置是 j  (j=2*id-i),mx关于id对称点是my (my=2*id-mx).

     那么,从id两侧(从my到mx)一定是回文的。

    如果i+p[j]长度在mx之内就取它,如果i+p[j]长度不可控,在mx之外,就取mx-i

字符串--最长回文子串(暴力讲解+Manacher)

字符串--最长回文子串(暴力讲解+Manacher)

    总之取  p[i]=min(p[2*id-i],mx-i)

                     没有可利用的p[i]=1;接下来该怎样就怎样。

 

#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
char s[10000],s2[100000];
int p[10000];
int size;
void Manacher(char *s,int * p)
{
	 size=strlen(s);
	p[0]=1;
	int id=0;
	int mx=1;
	for(int i=1;i<size;i++)
	{
		if(mx>i)
		{
			p[i]=min(p[2*id-i],mx-i);
		}
		else
		{
			p[i]=1;
		}
		for(;s[i+p[i]]==s[i-p[i]]&&(i-p[i]>=0);p[i]++);
		if(mx<i+p[i])
		{
			mx=i+p[i];
			id=i;
		}
	}
	
} 

int main()
{
	while(1)
	{
	scanf("%s",s2);
	size=strlen(s2);
	
	for(int i=0;i<2*size+1;i++)
	{
		s[i]='#';
		s[++i]=s2[i/2];
	}
printf("%s\n",s);
	Manacher(s,p);

for(int i=0;i<size;i++) 
	printf("%d%c",p[i]-1," \n"[i==size-1]); 
    }
}

字符串--最长回文子串(暴力讲解+Manacher)