字符串相关

字符串相关

这个部分放置的是与字符串相关的版子

5. 7

字典树

// 字典树trie
struct trie{
    static const int N = 1e6 + 100;
    int mp[N][30];
    int e[N];
    int cnt = 1;
    // 字典树建立
    void build(string s, int len){
        int p = 0;
        for(int i = 0; i < len; i++){
            int c = s[i] - 'a';
            if(mp[p][c] == 0)
                mp[p][c] = cnt++;
            p = mp[p][c];
        }
        e[p]++;
    }
    // 字典树查询
    int query(string s, int len){
        int p = 0;
        for(int i = 0; i < len; i++){
            int c = s[i] - 'a';
            if(mp[p][c] == 0)
                return false;
            p = mp[p][c];
        }
        return e[p];
    }
} Trie;

AC自动机(加了拓扑排序优化)

// AC自动机
namespace AC{
    static const int N = 1e6 + 100;
    //mp是字典树,e是表明结点是不是模式串结尾结点
    //cnt是结点个数
    //fail是AC自动机的失配指针
    //表示的状态是当前状态的在字典树上的最长后缀的状态
    //idx是编号为下标所指的模式串的结尾结点
    //in是按照fail指针所建立有向边,结点的入度
    int mp[N][30], e[N], res[N], cnt = 0, fail[N], idx[N], in[N];
    // 字典树建立
    void Insert(string s, int len, int id){
        int p = 0;
        for(int i = 0; i < len; i++){
            int c = s[i] - 'a';
            if(mp[p][c] == 0)
                mp[p][c] = ++cnt;
            p = mp[p][c];
        }
        e[p] = 1;
        idx[id] = p;
    }
    //建立fail
    void build(){
        queue <int> q;
        for(int i = 0 ; i < 26; i ++)
            if(mp[0][i])
                q.push(mp[0][i]);
        while(!q.empty()){
            int p = q.front();
            q.pop();
            for(int i = 0; i < 26; i++){
                if(mp[p][i]){
                    fail[mp[p][i]] = mp[fail[p]][i], q.push(mp[p][i]), in[fail[mp[p][i]]]++;
                }
                else
                    mp[p][i] = mp[fail[p]][i];
            }
        }
    }
    //查询
    void query(string s, int len){
        int p = 0;
        int ans = 0;
        for(int i = 0 ; i < len; i++){
            int c = s[i] - 'a';
            p = mp[p][c];
            res[p]++;
        }
        // return ans;
    }
    // 拓扑排序优化
    void topu(int n){
        queue<int> q;
        for(int i = 1; i <= cnt; i++)
            if(in[i] == 0)
                q.push(i);
        while(!q.empty()){
            int k = q.front();
            q.pop();
            int u = fail[k];
            res[u] += res[k];
            in[u]--;
            if(in[u] == 0)
                q.push(u);
        }
    }
}

5.8

KMP

namespace KMP{
    static const int N = 1e6 + 100;
    int next[N];
    void cal_next(string s, int len){
        next[0] = -1;
        int k = -1;
        for(int i = 1; i < len; i++){
            while(k > -1 && s[k + 1] != s[i])
                k = next[k];
            if(s[k + 1] == s[i])
                k = k + 1;
            next[i] = k;
        }
    }
    int find(string s, int lens, string p, int lenp){
        int k = -1;
        cal_next(p, lenp);
        for(int i = 0; i < lens; i++){
            while(k > -1 && p[k + 1] != s[i])
                k = next[k];
            if(p[k + 1] == s[i])
                k = k + 1;
            if(k == lenp - 1){
                //寻找下一个位置
                cout << i - lenp + 2 << '\n';
                k = next[k];
                //return i - lenp + 1;
            }
        }
        return -1;
    }
}

5.11

扩展KMP

namespace EX_KMP{
    typedef long long ll;
    const int N = 2e7 + 100;
    // next是要匹配的模式串的所有后缀和自身的最长公共前缀长度
    // exi是匹配串的所有后缀和模式串的最长公共前缀长度
    ll next[N], exi[N];
    void cal_next(string s, int len){
        int k = 1, p = 0, l;
        next[0] = len;
        while(p + 1 < len && s[p] == s[p + 1]) p++;
        next[1] = p;
        for(int i = 2; i < len; i++){
            p = k + next[k] - 1;
            l = next[i - k];
            if(i + l <= p)
                next[i] = l;
            else{
                int j = max(0, p - i + 1);
                while(i + j < len && s[i + j] == s[j]) j++;
                next[i] = j;
                k = i;
            }
        }
    }
    //要求出b中的每一个后缀和a的最长公共前缀
    void cal_exi(string a, string b, int lena, int lenb){
        int k = 0, p = 0, l;
        while(p < lena && p < lenb && a[p] == b[p]) p++;
        exi[0] = p;
        for(int i = 1; i < lenb; i++){
            p = k + exi[k] - 1;
            l = next[i - k];
            if(i + l <= p){
                exi[i] = l;
            }
            else{
                int j = max(0, p - i + 1);
                while(i + j < lenb && j < lena  && b[i + j] == a[j]) j++;
                exi[i] = j;
                k = i;
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值