012.匹配

匹配两个字符串

  • 母串为 s 、子串为 t
  • 当 t 在 s 中出现至少一次,匹配成功
  • 匹配失败返回 -1

朴素匹配

当 t 的长度很短时,在 s 上枚举起点

int match(string &s,string &t){
    int lt=t.length();
    int ls=s.length();
    for(int st=0;st+lt<=ls;st++){
        int i=st,j=0;
        while(j<lt&&s[i]==t[j])j++,i++;
        if(j==lt)return st; 
    }
    return -1;
}

kmp

用于 t 较长时

vector<int> get_next(string &t){
    int n=t.length();
    vector<int>next(n);
    next[0]=-1,next[1]=0;
    int j=2,cn=0;
    while(j<n){
        if(t[j-1]==t[cn])next[j++]=++cn;
        else if(cn)cn=next[cn];
        else next[j++]=0;
    }
    return next;
}
int kmp(string&s,string t){
    vector<int>next=get_next(t);
    int ls=s.length(),lt=t.length();
    int i=0,j=0;
    while(i<ls&&j<lt){
        if(s[i]==t[j])j++,i++;
        else if(j==0)i++;
        else j=next[j];
    }
    return j==lt?i-j:-1;
}

当然,可以合成一个函数

int kmp(string&s,string t){
    int ls=s.length(),lt=t.length();
    vector<int>next(lt);
    next[0]=-1,next[1]=0;
    int j=2,cn=0;
    while(j<lt){
        if(t[j-1]==t[cn])next[j++]=++cn;
        else if(cn)cn=next[cn];
        else next[j++]=0;
    }
    int i=0,j=0;
    while(i<ls&&j<lt){
        if(s[i]==t[j])j++,i++;
        else if(j==0)i++;
        else j=next[j];
    }
    return j==lt?i-j:-1;
}

RabinKarp

利用哈希思想解码

int RabinKarp(string &s,string &t){
    int R=256;
    int L=t.length();
    int mod=1658598167;//一个较大的素数,减少哈希冲突
    int RL=1;
    for(int i=1;i<L;++i){
        RL=(RL*R)%mod;
    }
    long key_t=0;
    for(int i=0;i<L;i++){
        key_t=(key_t*R+t[i])%mod;
    }
    long key=0;
    int l=0,r=0;
    while(r<(int)s.length()){
        key=(key*R+s[r++]);
        while(r-l==L){
            if(key==key_t&&t.compare(s.substr(l,L))==0)//哈希冲突,需cmp
            return l;
            key=(key-RL*s[l++])%mod;
        }
    }
    return -1;
}
posted @ 2025-12-16 18:48  射杀百头  阅读(3)  评论(0)    收藏  举报