zoukankan      html  css  js  c++  java
  • KMPnext数组自看

     

    next[i]表示去掉第i个元素后,自已的前缀和后缀完全匹配的最大长度

    字符串    a b a b a b z a b a b a b a
    next    -1 0 0 1 2 3 4 0 1 2 3 4 5 6 0

    前缀和后缀是啥意思呢

    abababz 前缀有 a ab aba abab ababa ababab 不算最后一个
          后缀有 z bz abz babz ababz bababz 不算第一个
    void getNext()
    {
        int j, k;
        j = 0; k = -1; next[0] = -1;
        while(j < tlen)
            if(k == -1 || T[j] == T[k])
                next[++j] = ++k;
            else
                k = next[k];
    
    }

    根据代码一个个匹配就好了

    关键在于next的回溯  为什么要这样回溯

    我们再看 字符串  a b a b a b z a b a b a b a

    每一个最长长度有两种来源  1、如果当前字符匹配 则由上一个最长长度加一    2、如果不匹配 则看次长长度的下一个字符是否与当前字符匹配。。不匹配就看次次长长度。。以此类推

    为什么呢。。。因为我们想要得到到当前位置的最长匹配长度。。

    那为什么k = next[k]就能到次长长度的下一个位置呢。。 

    我们就看上边那个个字符串  z的下标为6  next[6] = 4表示 去掉位置6的字符后所能匹配的最大长度

    那么 这个长度4是由上一个位置推出来的

    那么上一个位置是不是就是当前位置的次长长度

    既然是上一个位置 为什么 不是k = j - 1而是k = next[k]呢

    因为j代表后缀的位置 而k是前缀的位置  因为是找一个次大的前缀来匹配当前后缀

    而next[k]是除去k之后的最大匹配长度 即下标k前的最大匹配长度(当然 一定到k-1)

    其实意思很好懂。。。。记得平行吗。。a//b  b//c  a//c

    那next[k]不就是能和j匹配的前缀的位置吗。。。

    所以这个长度就是

    匹配就和人情世故一样。。。能通融一下通融一下。。。大的不行那就次大。。次大不行。。。那就次次大。。嗯。。就是这样。。kmp就是遵循了这个法则。。是的。。

    bin神kmp模板

    /*
    pku3461(Oulipo), hdu1711(Number Sequence)
    这个模板 字符串是从0开始的
    Next数组是从1开始的
    
    
    */
    #include <iostream>
    #include <cstring>
    using namespace std;
    
    const int N = 1000002;
    int next[N];
    char S[N], T[N];
    int slen, tlen;
    
    void getNext()
    {
        int j, k;
        j = 0; k = -1; next[0] = -1;
        while(j < tlen)
            if(k == -1 || T[j] == T[k])
                next[++j] = ++k;
            else
                k = next[k];
    
    }
    /*
    返回模式串T在主串S中首次出现的位置
    返回的位置是从0开始的。
    */
    int KMP_Index()
    {
        int i = 0, j = 0;
        getNext();
    
        while(i < slen && j < tlen)
        {
            if(j == -1 || S[i] == T[j])
            {
                i++; j++;
            }
            else
                j = next[j];
        }
        if(j == tlen)
            return i - tlen;
        else
            return -1;
    }
    /*
    返回模式串在主串S中出现的次数
    */
    int KMP_Count()
    {
        int ans = 0;
        int i, j = 0;
    
        if(slen == 1 && tlen == 1)
        {
            if(S[0] == T[0])
                return 1;
            else
                return 0;
        }
        getNext();
        for(i = 0; i < slen; i++)
        {
            while(j > 0 && S[i] != T[j])
                j = next[j];
            if(S[i] == T[j])
                j++;
            if(j == tlen)
            {
                ans++;
                j = next[j];
            }
        }
        return ans;
    }
    int main()
    {
        
        int TT;
        int i, cc;
        cin>>TT;
        while(TT--)
        {
            cin>>S>>T;
            slen = strlen(S);
            tlen = strlen(T);
            cout<<"模式串T在主串S中首次出现的位置是: "<<KMP_Index()<<endl;
            cout<<"模式串T在主串S中出现的次数为: "<<KMP_Count()<<endl;
        }
        return 0;
    }
    /*
    test case
    aaaaaa a
    abcd d
    aabaa b
    */
    自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。
  • 相关阅读:
    Unit of Work
    Layered Supertype
    Domain Model
    ASP.Net设计模式读书笔记
    VS2010无法使用nuget安装第三方包的问题
    数据库对象命名
    sql50题
    RESTFul API
    EasyUI日历控件
    ASP.NET MVC 防止前端点击劫持
  • 原文地址:https://www.cnblogs.com/WTSRUVF/p/9460907.html
Copyright © 2011-2022 走看看