Manacher算法学习 & HDU 3068

tonyfang posted @ 2015年8月11日 19:43 in Algorithm with tags c++ Algorithm HDU , 788 阅读

Manacher算法:(求最长回文串O(n)算法)

定义数组p[i]表示以i为中心的(包含i这个字符)回文串半径长

将字符串s从前扫到后来计算p[i],则最大的p[i]就是最长回文串长度,则问题是如何去求p[i]?

由于s是从前扫到后的,所以需要计算p[i]时一定已经计算好了p[1]....p[i-1]

假设现在扫描到了i+k这个位置,现在需要计算p[i+k]

定义maxlen是i+k位置前所有回文串中能延伸到的最右端的位置,即maxlen=p[i]+i;//p[i]+i表示最大的

分两种情况:

   1.i+k这个位置不在前面的任何回文串中,即i+k>maxlen,则初始化p[i+k]=1;(本身是回文串)然后p[i+k]左右延伸

while(s[i+k+p[i+k]] == s[i+k-p[i+k]]) p[i+k]++;

   2.i+k这个位置被前面以位置i为中心的回文串包含,即maxlen>i+k,这样的话p[i+k]就不是从1开始

 

由于回文串的性质,可知i+k这个位置关于i与i-k对称,

所以p[i+k]分为以下3种情况得出

//黑色是i的回文串范围,蓝色是i-k的回文串范围,


 

=============以上内容转载自:这里=================

下面是HDU 3068

AC通道

 

# include <stdio.h>
# include <string.h>
# define min(a,b) (a<b?a:b)
using namespace std;
const int MAX=120010;
char s2[MAX],s[MAX*2];
int p[MAX*2];
int main() {
	while(scanf("%s",s)!=EOF) {
		int len=strlen(s);
		for (int i=len;i>=0;--i) {
			s[i+i+2]=s[i];
			s[i+i+1]='#';
		}
		s[0]='*';
		int id=0,maxlen=0;
		for (int i=2;i<2*len+1;++i) {
			if(p[id]+id>i) p[i]=min(p[2*id-i],p[id]+id-i);
			else p[i]=1;
			while(s[i-p[i]]==s[i+p[i]]) p[i]++;
			if(id+p[id]<i+p[i]) id=i;
			if(maxlen<p[i]) maxlen=p[i];
		}
		printf("%d\n",maxlen-1);
	}
	return 0;
}
navodayaresults5th.i 说:
2023年4月17日 21:14

Board of jnvstresults5th Education, jnvstresults5th has successfully conducted the state class 5th grade annual final public examination tests for all government and private school jnvstresults5th, Hindi Medium and English Medium students navodayaresults5th.in to the academic year and more boys and girl students are participated from all rural and urban area schools in the state, according to the reports this year also huge number of boys and girls are applied and participated in class 5th grade annual final public exams.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter