• kmp


    还真是写了又忘忘了再写......

     kmp算法用于加速字符串的匹配,优化暴力匹配

    文本串 s  "abcaabcabeabcabd"

    模式串 t   "abcabd"

    t 匹配 s,找 t 在 s 中出现的最早位置

    暴力匹配试试

    指针i,j 从0开始右移匹配

    abcaabcabeabcabd
            i
    abcabd
            j

    此时 s [ i ] 和 t [ j ] 不匹配,j 跳到 0 继续匹配,但这样很耗时间

    瞎搞一下,发现 t [ j ] 前面的都已经和 s [ i ] 前面的匹配好了, 这样如果 j 前面子串的前缀和后缀相同的最大长度都可以不用匹配

    e.g. (1) t 串中 abcab的最后一位 t [ 4 ] b 不匹配, 前面的abca都匹配好了,即 s [ 3 ] = t [ 3 ] =a, t [ 3 ] a是后缀,  t [ 0 ] a 是和其相等的前缀,肯定和 s [ 3 ] 相等

    这位就可以不用匹配了

    直接跳到 t [ 1 ] 去匹配

    更具象一点

    (2)abcaabcabeabcabd
                      i
            abcabd
                      j

    此时  s [ i ] 与 t [ j ] 不匹配,后缀 t [ 3 ] t [ 4 ] = ab 与 s [ 7 ] s [ 8 ] = ab 匹配好了, 最大前缀 t [ 0 ] t [ 1 ] = ab 肯定也匹配好了

    接下来 j 直接跳到 2 与 s [ 9 ] 匹配就可以了

    我们用一个数组nxt表示 t 串中 位置 i 不匹配时该跳到哪一位

    线性求nxt数组,根据最大前后缀匹配求(找个串模拟一下更好理解

    void getnxt(string s)
    {
        ll n=s.size();
        ll j=0, k=-1; //j比k大一位
       nxt[
    0]=-1; //初始化为-1, 方便判断
       while(j<n-1) { if(k==-1 || s[j]==s[k]) // k==-1即无匹配前后缀, s[j]==s[k]有匹配 { j++, k++; // j一直在加; j ,k 先++ nxt[j]=k; //已匹配的下一位的跳转位置 } else k=nxt[k]; //k会回退 } return ; }

    nxt数组优化

    在e.g.(1)中, 

    abcaabcabeabcabd
            i
    abcabd
            j=4

    t [ 4 ]不匹配, nxt [ 4 ]=1,j  应该跳到1去匹配, 但是 t [ 1 ] == t [ 4 ], t [ 4 ]失配, t [ 1 ]肯定也失配

    这样就又多耗时间了

    咋优化咧

    在求 nxt 的时候判断一下就好啦

    void getnxt(string s)
    {
        ll n=s.size();
        ll j=0, k=-1; //j比k大一位
       nxt[0]=-1; //初始化为-1, 方便判断
       while(j<n-1)
        {
            if(k==-1 || s[j]==s[k])  // k==-1即无匹配前后缀, s[j]==s[k]有匹配
            {
                j++, k++;          // j一直在加; j ,k 先++
           if(s[j] != s[k])
             nxt[j]=k; //已匹配的下一位的跳转位置
           else nxt[j]=nxt[k]; //相等的话跳到nxt[k]的位置
         } else k=nxt[k]; //k会回退 } return ; }

     完整kmp代码:

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<map>
    #include<queue>
    #include<stack>
    #include<list>
    #include<set>
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> P;
    typedef long double ld;
    #define mem(x) memset(x, 0, sizeof(x))
    #define me(x) memset(x, -1, sizeof(x))
    #define fo(i,n) for(i=0; i<n; i++)
    #define sc(x) scanf("%lld", &x)
    #define sca(n,m) scanf("%lld%lld", &n, &m)
    #define pr(x) printf("%lld
    ", x)
    #define pri(x) printf("%lld ", x)
    #define lowbit(x) x&-x
    const ll MOD = 1e9 + 7;
    const ll oo = 1e18;
    const ll N = 4e5 + 5;
    ll nxt[N];
    void getnxt(string s)
    {
        ll n=s.size();
        ll j=0, k=-1;
        nxt[0]=-1;
        while(j<n-1)
        {
            if(k==-1 || s[j]==s[k])
            {
                j++, k++;
                if(s[j]!=s[k]) nxt[j]=k;
                else nxt[j]=nxt[k];
            }
            else k=nxt[k];
        }
        return ;
    }
    ll kmp(string s, string t)
    {
        ll n=s.size(), m=t.size();
        ll i=0, j=0;
        while(i<n && j<m)
        {
            if(j==-1 || s[i]==t[j])
                i++, j++;
            else j=nxt[j];
        }
        if(j==m) return i-j;//返回匹配起始下标
        else return -1;
    }
    int main()
    {
        ll i, j, k;
        ll n, m;
        string s, t;
        while(cin>>s>>t)
        {
            getnxt(t);
            n=s.size(); m=t.size();
            k=kmp(s,t);
            cout<<k<<endl;
        }
        return 0;
    }
  • 相关阅读:
    Building Java Projects with Gradle
    Vert.x简介
    Spring及Spring Boot 国内快速开发框架
    dip vs di vs ioc
    Tools (StExBar vs Cmder)which can switch to command line window on context menu in windows OS
    SSO的定义、原理、组件及应用
    ModSecurity is an open source, cross-platform web application firewall (WAF) module.
    TDD中测试替身学习总结
    Spring事务银行转账示例
    台式机(华硕主板)前面板音频接口(耳机和麦克风)均无声的解决办法
  • 原文地址:https://www.cnblogs.com/op-z/p/11307464.html
Copyright © 2020-2023  润新知