• 字符串学习笔记


    1. manacher 马拉车

    P3805 【模板】manacher 算法

    思路

    1. 回文串长度有奇有偶,奇回文串有对称中心,那偶回文串呢,所以我们就在每两个字符串之间加一个#,再在整个串前面加一个 % ,这样奇偶串就可以用按一种方法处理了,比如abcd --> %a#b#c#d#
    2. 我们可以用O(n) 求出r数组,r[i]是以i为对称中心的回文串半径(长度包括i),令mx是回文串覆盖的最右边界的右边一位,p是覆盖最右边界的回文串的对称中心,这时我们要求r[i],暴力会TLE,当p<mx时,我们考虑r[i]可以从r[2 * p - i] 处已确认对称的部分转移过来,r[i]=min (mx-p,r[ 2 * p - i ]),之后继续尝试暴力向外拓展,看r[i]是否能增大

    code

    #include<bits/stdc++.h>
    #define N 22000010
    #define mod 998244353
    #define int long long
    using namespace std;
    int n,ans;
    int r[N];
    char a[N];
    template<class T> inline void read(T &x)
    {
    	x=0;int g=1;char s=getchar();
    	for (;s<'0'||s>'9';s=getchar()) if (s=='-') g=-1;
    	for (;s>='0'&&s<='9';s=getchar()) x=(x<<1)+(x<<3)+(s^48);
    	x*=g;
    }
    signed main()
    {
    	int i,j,op,x,y,z;
    	scanf("%s",a+1);
    	n=strlen(a+1);
    	for (i=n;i;i--) a[2*i]=a[i],a[2*i+1]='#';a[1]='#';a[0]='$';	
    	int p=1,mx=1;
    	n=2*n+1;
    	for (i=1;i<=n;i++)
    	{
    		if (mx<=i) r[i]=1;
    		else r[i]=min(mx-i,r[2*p-i]);
    		while(a[i+r[i]]==a[i-r[i]]) r[i]++;
    		if (i+r[i]>mx)
    		{
    			mx=i+r[i];p=i;
    		}	
    		ans=max(ans,r[i]);
    	}
    	printf("%lld
    ",ans-1);
    	return 0;
    }
    

    2. kmp

    P3375 【模板】KMP字符串匹配

    思路

    kmp时间复杂度小的精髓在于,每次失配以后,不是从头开始重新匹配,而是用一段尽量长的与已匹配部分后缀相同的模式串前缀与文本串的已匹配部分匹配,并且尝试继续向后拓展,如果又一次失败,那就换成较小的前缀去尝试拓展

    我们要先求出kmp数组,就要自己匹配自己,kmp[i]是以i结尾的后缀相等的最长前缀的右端点,再用求出的kmp数组去求出每个模式串在文本串里出现的位置

    code

    #include<bits/stdc++.h>
    #define int long long
    #define N 2000010
    #define re register 
    using namespace std;
    int n,m,ans,kmp[N];
    char a[N],b[N];
    template <class T> inline void read(T &x)
    {
    	x=0;int g=1;char s=getchar();
    	for (;s<'0'||s>'9';s=getchar()) if (s=='-') g=-1;
    	for (;s>='0'&&s<='9';s=getchar()) x=(x<<1)+(x<<3)+(s^48);
    	x*=g;
    }
    signed main()
    {
    	re int i,j,x,y,z,op;
    	scanf("%s",a+1);n=strlen(a+1);
    	scanf("%s",b+1);m=strlen(b+1);
    	j=0;
    	for (i=2;i<=m;i++)
    	{
    		while(j&&b[i]!=b[j+1]) j=kmp[j];
    		if (b[i]==b[j+1])j++;
    		kmp[i]=j;
    	} 
    	j=0;
    	for (i=1;i<=n;i++)
    	{
    		while(j&&a[i]!=b[j+1]) j=kmp[j];
    		if (a[i]==b[j+1]) j++;
    		if (j==m)
    		{
    			printf("%lld
    ",i-m+1);
    			j=kmp[j];
    		}
    	}
    	for (i=1;i<=m;i++) printf("%lld ",kmp[i]);
    	return 0;
    }
    
  • 相关阅读:
    安卓 Context 和 Application的关系
    Android Intent应用
    android launchmode(四种启动模式)应用场景及实例
    返回数据给上一个活动
    Intent传参数
    安卓activity生命周期
    如何将nideshop部署到本地
    navicat链接数据库错误2013
    数据库设计三大范式
    nodejs版本升级
  • 原文地址:https://www.cnblogs.com/Ritalc/p/15003831.html
Copyright © 2020-2023  润新知