字符串算法KMP、Manacher

                                               目录

1、KMP算法

 1.1C++代码模板     洛谷KMP板子题

1.2Python代码模板     蓝桥KMP题1        蓝桥KMP题2

           2、Manacher

 1、C++模板       洛谷 Manacher板子题

2、Python模板      蓝桥最长回文子串


字符串算法是一种用于解决字符串相关问题的算法。其中,KMP算法和Manacher算法是两种常见的字符串算法,也分别用于解决是非常匹配和最长回文子串问题。是蓝桥杯常考察的点。

1、KMP算法

        KMP算法是一种字符串匹配算法,用于在一个字符串中查找另外一个字符串出现的位置。它的基本思想是通过对模式字符串进行预处理,构造一个pnext数组来指导匹配过程中的跳转问题,时间复杂度可以优化到近似到O(n+m)。而基础的暴力算法每次的跳转都是1,因而复杂度最差会达到O(nm)。

        KMP算法的主要步骤如下:

        a.预处理模式串,构造pnext数组。

        b.从文本串的第一个字符开始匹配,逐个字符的和模式串进行匹配。

        c.如果匹配成功,继续匹配下一个字符,直到模式串匹配完成。

        d.如果匹配失败,利用pnext数组进行跳转,重新匹配。

 1.1C++代码模板     洛谷KMP板子题

// s[]是长文本,p[]是模式串,n是s的长度,m是p的长度
求模式串的pnext数组:
for (int i = 2, j = 0; i <= m; i ++ )
{
    while (j && p[i] != p[j + 1]) j = pnext[j];
    if (p[i] == p[j + 1]) j ++ ;
    pnext[i] = j;
}
// 匹配
for (int i = 1, j = 0; i <= n; i ++ )
{
    while (j && s[i] != p[j + 1]) j = pnext[j];
    if (s[i] == p[j + 1]) j ++ ;
    if (j == m)
    {
        j = pnext[j];
        // 匹配成功后的逻辑
    }
}

1.2Python代码模板     蓝桥KMP题1        蓝桥KMP题2

p.insert(0,0)
s.insert(0,0)
pnext = [0]*(len(p)+10)
i,j = 2,0
while i<=m:
    while j and p[i]!=p[j+1]:
        j = pnext[j]
    if p[i] == p[j+1]:
        j+=1
    pnext[i] = j
    i+=1
i,j=1,0
while i<=n:
    while j and s[i]!=p[j+1]:
        j = pnext[j]
    if s[i] == p[j+1]:
        j+=1
    if j==m:
        print(i-j,end=' ')
        j = pnext[j]
    i+=1

2、Manacher

        Manacher算法是一种用于求最长回文子串的算法,它可以在O(n)的时间复杂度内解决该问题,常规暴力则是枚举每个中点然后拓展附近点算法的时间复杂度为O(n*2)。      

        Manacher算法的基本思想是利用回文串的对称性质,在求解的过程中对已经匹配过的位置进行存储和复用从而避免了大量的重复技术。

        主要步骤如下:

        a.对原字符串进行预处理,构造一个新的字符串,使得每个字符串之间都有一个特殊字符(例如"#")隔开,这样确保新字符串的每个回文串都是奇数长度的。

        b.维护一个回文半径数组p,其中p[i]表示以i为中心的回文串的半径长度。

        c.维护一个右边界r和中心点mid,分别表示已知的最长回文串的右边界和中心点。

        d.遍历新字符串,根据已知的回文串的对称性质来更新p[i]的值,以及r和mid的值。

        e.遍历p数组,找出其中的最大值,即为原字符串的最长回文子串的长度。

Case1:mid < i < r

        由于[ mid - r,mid + r] 是回文的,设j为i以mid为中点的对称点,根据对称性,则我们可以得到:[ j - pj,j + pj ] = [ i -pi,i + pi ] 。 但是 i + pi > r 的时候,我们无法保证上述情况相等(设r以mid)为中心的对称点为x,因为j - pj < x,所以无法保证相等。所以在case1的情况下我们可以直接让  p[ i ] = min (p[ j ],r - i +1)。

Case2:i >= r

        这个时候我们不能求出对称点,直接暴力拓展。p[ i ] = 1.

 1、C++模板       洛谷 Manacher板子题

void build() {
	scanf("%s",c+1);
	n=strlen(c + 1);
	s[++ cnt]='~';
	s[++ cnt]='#';
	for(int i=1;i<=n;i++){
		s[++cnt] = c[i];
		s[++cnt] = '#';
	}
	s[++ cnt] = '!';
}
void solve() {
	for(int i=2;i<=cnt-1;i++){
		if(i <= r)
			p[i] = min(p[mid * 2 - i], r - i + 1);
		else
			p[i] = 1;
		while(s[i - p[i]] == s[i + p[i]]) ++ p[i];
		if(i + p[i] > r) 
			r = i + p[i] - 1, mid = i;
		res = max(res, p[i]);
	}
	printf("%d",res-1);
}

2、Python模板      蓝桥最长回文子串

s=input()
new_s="#".join([x for x in s])
new_s=" ~#"+new_s+"#!"
mid,r,res,cnt = 0,0,0,len(new_s)
p=[0]*(1000010)
for i in range(2,len(new_s)-1):
    if i<r:
      p[i]=min(p[mid*2-i],r-i+1)
    else:
      p[i]=1
    while new_s[i-p[i]]==new_s[i+p[i]]:
      p[i]+=1
    if i+p[i]>r:
      mid=i
      r=i+p[i]-1
    res = max(res,p[i])
print(res-1)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学数学的懒哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值