马拉车(Manacher)算法

马拉车(Manacher)算法

前言:马拉车算法与KMP算法都是解决字符串问题的经典算法,为什么把它们俩个放在一起呢?这是因为它们的思想都是用前面已知的信息去更新后面的信息。

马拉车(Manacher)算法

马拉车算法主要用于解决最长回文串的问题,并且是以 O ( n ) O(n) O(n)的时间复杂度解决。

马拉车算法的优势:

  • 不用考虑字符串是单数还是双数
  • 可以以 O ( n ) O(n) O(n)的时间复杂度得到最长回文串的长度,并能找到它
具体步骤:
1.解决字符串单数与双数问题

因为单数的回文串最中间的位置是字符,双数的回文串是中间两个字符中间的位置。为了不考虑字符串是单数还是双数,要对原字符串进行预处理。

改造字符串

在字符串之间和串两端插入’#',改造后无论原先是偶字符串还是奇字符串都会变成奇字符串,方便统一处理。

例如:

奇数串 aba #a#b#a#

偶数串 abba #a#b#b#a#

相关代码:

	scanf("%s",a+1);
	int len1=strlen(a+1);
	int k=0;
	s[0]='$';
	s[++k]='#';
	for(int i=1;i<=len1;i++){//主要消除奇偶的问题 
		s[++k]=a[i];
		s[++k]='#';
	}
2.算法流程

d [ i ] d[i] d[i]数组为以 i i i为中心的最长回文串的半径,比如说 a b a aba aba,以 b b b为中心的最长回文串的半径为 2 2 2,记作 d [ 2 ] = 2 d[2]=2 d[2]=2

1.接下来我们维护一个 [ l , r ] [l,r] [l,r]的区间,这个区间内是能够通过之前 d [ i ] d[i] d[i]去更新现在的 d [ j ] d[j] d[j]。因为在区间 [ l , r ] [l,r] [l,r]内是一个回文序列,回文序列的特点是左右对称,那么 i i i的对称点为 r − i + l r-i+l ri+l

如果 d [ r − i + l ] < r − i + 1 d[r-i+l]<r-i+1 d[ri+l]<ri+1 d [ i ] = d [ i − l + 1 ] d[i]=d[i-l+1] d[i]=d[il+1]

否则 d [ r − i + l ] > = r − i + 1 d[r-i+l]>=r-i+1 d[ri+l]>=ri+1 d [ i ] = r − i + 1 d[i]=r-i+1 d[i]=ri+1,然后从 r + 1 r+1 r+1向后枚举。

2.如果 i > r i>r i>r,则从 i i i开始暴力枚举

3.求出 d [ i ] d[i] d[i]之后,如果 i + d [ i ] − 1 > r i+d[i]-1>r i+d[i]1>r,则更新区间范围, l = i − d [ i ] + 1 , r = i + d [ i ] − 1 l=i-d[i]+1,r=i+d[i]-1 l=id[i]+1,r=i+d[i]1

	d[1]=1;
	for(int i=2,r1=1,l1;i<=k;i++){
		if(i<=r1) d[i]=min(r1-i+1,d[r1-i+l1]);
		while(s[d[i]+i]==s[i-d[i]]) d[i]++;
		if(i+d[i]-1>r1){
			r1=i+d[i]-1;
			l1=i-d[i]+1;
		} 
	}

视频讲解

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值