kmp&扩展kmp&manacher&最大最小表示法模板

集合一下最近做题用到的模板,都是字符串相关的。

//kmp算法:
//优化版:

void GetNextval(string P, int nextval[])
{
    int p_len = P.size();
    int i = 0;   //P的下标
    int j = -1;
    nextval[0] = -1;

    while (i < p_len)
    {
        if (j == -1 || P[i] == P[j])
        {
            i++;
            j++;
            if (P[i] != P[j])
                nextval[i] = j;
            else
                nextval[i] = nextval[j];  //既然相同就继续往前找真前缀
        }
        else
            j = nextval[j];
    }
}

//未优化版

void get_next(char a[])
{
    int l=strlen(a);
    int i=0;
    int j=-1;
    next[0]=-1;
    while(i<l)
    {
        if(j==-1||a[i]==a[j])
        {
            i++;
            j++;
            next[i]=j;
        }
        else
            j=next[j];
    }
}
int kmp(char s[],char t[])
{
    int ls=strlen(s);
    int lt=strlen(t);
    int j=0;
    int i=0;
    get_next(s);
    while(i<lt&&j<ls)
    {
        if(j==-1||s[j]==t[i])
        {
            i++;
            j++;
        }
        else
            j=next[j];
    }
    if(j==ls)       //匹配成功返回第一次出现的位置
        return i-j;
    return 0;
}

//扩展kmp算法(1):

void GETNEXT(char *str)
{
    int i=0,j,po,len=strlen(str);
    next[0]=len;//初始化next[0]
    while(str[i]==str[i+1]&&i+1<len)//计算next[1]
    i++;
    next[1]=i;
    po=1;//初始化po的位置
    for(i=2;i<len;i++)
    {
        if(next[i-po]+i<next[po]+po)//第一种情况,可以直接得到next[i]的值
        next[i]=next[i-po];
        else//第二种情况,要继续匹配才能得到next[i]的值
        {
            j=next[po]+po-i;
            if(j<0)j=0;//如果i>po+next[po],则要从头开始匹配
            while(i+j<len&&str[j]==str[j+i])//计算next[i]
            j++;
            next[i]=j;
            po=i;//更新po的位置
        }
    }
}
//计算extend数组
void EXKMP(char *s1,char *s2)
{
    int i=0,j,po,len=strlen(s1),l2=strlen(s2);
    GETNEXT(s2);//计算子串的next数组
    while(s1[i]==s2[i]&&i<l2&&i<len)//计算ex[0]
    i++;
    ex[0]=i;
    po=0;//初始化po的位置
    for(i=1;i<len;i++)
    {
        if(next[i-po]+i<ex[po]+po)//第一种情况,直接可以得到ex[i]的值
        ex[i]=next[i-po];
        else//第二种情况,要继续匹配才能得到ex[i]的值
        {
            j=ex[po]+po-i;
            if(j<0)j=0;//如果i>ex[po]+po则要从头开始匹配
            while(i+j<len&&j<l2&&s1[j+i]==s2[j])//计算ex[i]
            j++;
            ex[i]=j;
            po=i;//更新po的位置
        }
    }
}


//扩展kmp算法(2):

void GetNext(string & T, int & m, int next[])
{
    int a = 0, p = 0;
    next[0] = m;

    for (int i = 1; i < m; i++)
    {
        if (i >= p || i + next[i - a] >= p)
        {
            if (i >= p)
                p = i;

            while (p < m && T[p] == T[p - i])
                p++;

            next[i] = p - i;
            a = i;
        }
        else
            next[i] = next[i - a];
    }
}

/* 求解 extend[] */
void GetExtend(string & S, int & n, string & T, int & m, int extend[], int next[])
{
    int a = 0, p = 0;
    GetNext(T, m, next);

    for (int i = 0; i < n; i++)
    {
        if (i >= p || i + next[i - a] >= p) // i >= p 的作用:举个典型例子,S 和 T 无一字符相同
        {
            if (i >= p)
                p = i;

            while (p < n && p - i < m && S[p] == T[p - i])
                p++;

            extend[i] = p - i;
            a = i;
        }
        else
            extend[i] = next[i - a];
    }
}
//manacher算法:

void manacher(char *s)
{
    int len=strlen(s);
    for(int i=len;i>=0;--i){
        s[i+i+2]=s[i];
        s[i+i+1]='#';
    }
    s[0]='*';
    int k=1,maxlen=0;
    for(int i=2;i<len+len+1;++i){
        int maxr=k+p[k]-1;
        p[i]=min(p[2*k-i],max(maxr-i+1,1));
        while(s[i-p[i]] == s[i+p[i]])++p[i];
        if(i+p[i]>k+p[k])k=i;
        if(p[i]>maxlen)maxlen=p[i];
    }
}
//最大最小表示法:
int get_max_min(char s[],int flag)
{
    int i=0;
    int j=1;
    int len=strlen(s);
    int k=0;
    while(i<len&&j<len&&k<len)
    {
        int t=s[(j+k)%len]-s[(i+k)%len];
        if(t==0)
            k++;
        else
        {
            if(flag)
            {
                if(t>0) j+=k+1;
                else i+=k+1;
            }
            else
            {
                if(t>0) i+=k+1;
                else j+=k+1;
            }
            if(i==j) j++;
            k=0;
        }
    }
    return min(i,j);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值