ACM字符串学习笔记

字符串

KMP

void get_nex(string &s){
    int j=0,k=-1;
    nex[0]=-1;
    while(j<(int)s.size()){
        if(k==-1 || s[j]==s[k]){
            j++; k++;
            nex[j]=k;
        }else{
            k=nex[k];
        }
    }
}
int KMP(string &s1,string &s2){
    int i=0,j=0;
    get_nex(s2);
    while(i<(int)s1.size() && j<(int)s2.size()){
        if(j==-1 || s1[i]==s2[j]){
            i++,j++;
//            if(j>=(int)s2.size()){
//                ans.push_back( i-(int)s2.size() );
//                j=nex[j];
//            }
        }else{
            j=nex[j];
        }
    }
    if(j>=(int)s2.size()) return i-(int)s2.size();
    return -1;
}

哈希

哈希匹配

理论时间复杂度(m+n),B为一个质数,随意取,哈希算法不是100%准确,有一定概率会出错.
(当然我们也可以在哈希值相同的时候再用朴素双法再次进行检验,以达到100%的匹配准确)
大多数情况下,哈希检索的速度都是非常快的

int lena,lenb;
char a[1005],b[1005];//查找a中的b
int B=131;//质数基13331

void hash_pipei(){
    if(lenb>lena)
        return;
    ll hash_b=0,hash_a=0;
    ll t=1;//作中间变量存储B^t;
    for(int i=0;i<lenb;i++){
        hash_b=hash_b*B+b[i];
        t*=B;
        hash_a=hash_a*B+a[i];
    }

    if(hash_a==hash_b){
        printf("YES\n");
    }

    for(int i=lenb;i<lena;i++){
        hash_a=hash_a*B-t*a[i-lenb]+a[i];
        if(hash_a==hash_b){
            printf("%d YES\n",i);
        }
    }
}

时间复杂度(1)的询问子串哈希

多次询问子串哈希
const ll mod1 = 1e9+7;
const ll mod2 = 1e9+9;
char s[N];
ll base1[N],base2[N];
ll p_h1[N],p_h2[N];
ll p_h3[N],p_h4[N];//回文

inline ll query( int l,int r,int key ){//O(1) 询问hash值
    if( key ) return ((p_h1[r]-p_h1[l-1]*base1[r-l+1]%mod1)+mod1)%mod1;
    return ((p_h2[r]-p_h2[l-1]*base2[r-l+1]%mod2)+mod2)%mod2;
}

inline ll query2( int l,int r,int key ){//回文
    if( key ) return ((p_h3[r]-p_h3[l-1]*base1[r-l+1]%mod1)+mod1)%mod1;
    return ((p_h4[r]-p_h4[l-1]*base2[r-l+1]%mod2)+mod2)%mod2;
}
inline bool Palindrome( int l,int r ){//回文
    return ( query(l,r,1 )==query2( n-r+1,n-l+1,1 ) && query(l,r,0)==query2( n-r+1,n-l+1,0) );
}

void hash_val(){
    base1[0]=1;  base2[0]=1;
    ll B=13331;
    for(int i=1;i<=n;i++){
        base1[i]=base1[i-1]*B%mod1;
        base2[i]=base2[i-1]*B%mod2;
    }
    for(int i=1;i<=n;i++){
        p_h1[i]=( p_h1[i-1]*B + s[i] )%mod1;
        p_h2[i]=( p_h2[i-1]*B + s[i] )%mod2;
        
        //回文
        p_h3[i]=( p_h3[i-1]*B + s[n-i+1] )%mod1;
        p_h4[i]=( p_h4[i-1]*B + s[n-i+1] )%mod2;
    }
}

字典树

int nex[100000][26], cnt;
bool exist[100000];  // 该结点结尾的字符串是否存在

void insert(char *s, int len) {  // 插入字符串
    int p = 0,c;
    for (int i = 0; i < len; i++) {
        c = s[i] - 'a';
        if (!nex[p][c]) nex[p][c] = ++cnt;  // 如果没有,就添加结点
        p = nex[p][c];
    }
    exist[p] = 1;
}
bool find(char *s, int len) {  // 查找字符串
    int p = 0,c;
    for (int i = 0; i < len; i++) {
        c = s[i] - 'a';
        if (!nex[p][c]) return 0;
        p = nex[p][c];
    }
    return exist[p];
}

马拉车算法

string Manacher(string &s){
    string t="@#";
    for(int i=0;i<s.size();i++){
        t+=s[i];   t+="#";
    }

    vector<int> p(t.size(),0);
    int mx=0,id=0,resLen=0,resCenter=0;
    for(int i=1;i<t.size();i++){
        p[i]=mx>i?min(p[2*id-i],mx-i):1;
        while( t[i+p[i]]==t[i-p[i]] ) ++p[i];
        if(mx<i+p[i]){
            mx=i+p[i];
            id=i;
        }
        if(resLen<p[i]){
            resLen=p[i];
            resCenter=i;
        }
    }
    return s.substr( (resCenter-resLen)/2,resLen-1 );
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值