• [KMP] 对最长前后缀匹配表生成步骤的理解


    字符串匹配的KMP算法 - 阮一峰的网络日志 (ruanyifeng.com)icon-default.png?t=M276http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html没接触过kmp可以先看看这个


    例题:

    输入样例:

    3
    aba
    5
    ababa
    

    输出样例:

    0 2

     代码实现:

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    const int N = 1e5+10, M = 1e6+10;
    
    int n, m;
    int ne[N];
    char s[N], g[M];
    
    int main()
    {
        cin >> n >> s + 1 >> m >> g + 1;
        
        //模式串自匹配,初始化偏移数组ne[]
        for(int i = 2, j = 0; i <= n; i ++)
        {
            while(j && s[j+1] != s[i]) j = ne[j];
            if(s[j+1] == s[i]) j ++;
            ne[i] = j;
        }
        
        //两串匹配
        for(int i = 1, j = 0; i <= m; i ++)
        {
            while(j && s[j+1] != g[i]) j = ne[j];
            if(s[j+1] == g[i]) j ++;
            if(j == n)
            {
                cout << i-n << " "; //题意中下标从0开始,因此(i-n+1)-1
                j = ne[j];
            }
        }
    
        return 0;
    }


    下面我们输出关键的ne[ ]数组(即最长前后缀匹配表)初始化的步骤

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    const int N = 1e5+10, M = 1e6+10;
    
    int n, m;
    int ne[N];
    char s[N], g[M];
    
    int main()
    {
        cin >> n >> s + 1 >> m >> g + 1;
        
        //模式串自匹配,初始化偏移数组ne[]
        for(int i = 2, j = 0; i <= n; i ++)
        {
            cout << "-----------" << endl;
            while(j && s[j+1] != s[i]){
                printf("s[j(%d)+1] != s[i(%d)] '%c' != '%c'\n", j, i, s[j+1], s[i]);
                j = ne[j];
                printf("j = ne[j] (ne[%d]) = %d\n", j, ne[j]);
            }
            if(s[j+1] == s[i]){
                printf("s[j(%d)+1] == s[i(%d)] '%c' != '%c'\n", j, i, s[j+1], s[i]);
                j ++;
                printf("j++, j = %d\n", j);
            }
            ne[i] = j;
            printf("ne[i(%d)] = j(%d)\n", i, j);
        }
        cout << "-----------" << endl;
        for(int i = 1; i <= n; i ++) cout << ne[i] << " ";
        cout << "#" << endl;
        //两串匹配
        // for(int i = 1, j = 0; i <= m; i ++)
        // {
        //     while(j && s[j+1] != g[i]) j = ne[j];
        //     if(s[j+1] == g[i]) j ++;
        //     if(j == n)
        //     {
        //         cout << i-n << " ";
        //         j = ne[j];
        //     }
        // }
    
        return 0;
    }

    测试输入:

    10
    ababcabcab
    14
    abababababccba

    (注: 字符串下标从1开始)

    s[]

    a

    b

    a

    b

    c

    a

    b

    c

    a

    b

    ne[]

    0

    0

    1

    2

    0

    1

    2

    0

    1

    2

    下标

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    对比参照输出: 

    (括号内表示的是i / j此时的值)

    -----------
    ne[i(2)] = j(0)
    -----------
    s[j(0)+1] == s[i(3)] 'a' == 'a'
    j++, j = 1
    ne[i(3)] = j(1)
    -----------
    s[j(1)+1] == s[i(4)] 'b' == 'b'
    j++, j = 2
    ne[i(4)] = j(2)
    -----------
    s[j(2)+1] != s[i(5)] 'a' != 'c'
    j = ne[j(0)] = 0
    ne[i(5)] = j(0)
    -----------
    s[j(0)+1] == s[i(6)] 'a' == 'a'
    j++, j = 1
    ne[i(6)] = j(1)
    -----------
    s[j(1)+1] == s[i(7)] 'b' == 'b'
    j++, j = 2
    ne[i(7)] = j(2)
    -----------
    s[j(2)+1] != s[i(8)] 'a' != 'c'
    j = ne[j(0)] = 0
    ne[i(8)] = j(0)
    -----------
    s[j(0)+1] == s[i(9)] 'a' == 'a'
    j++, j = 1
    ne[i(9)] = j(1)
    -----------
    s[j(1)+1] == s[i(10)] 'b' == 'b'
    j++, j = 2
    ne[i(10)] = j(2)
    -----------
    0 0 1 2 0 1 2 0 1 2 #
  • 相关阅读:
    转:spring 的控制反转
    jsp 页面间传递参数
    Struts-config.xml配置文件《action-mappings》元素的详解
    转:装饰模式
    转:策略模式
    MyBatis的动态SQL详解
    MyBatis配置
    spring与mybatis三种整合方法
    sqlserver 脚本 多条记录遍历
    SQL Server 游标使用
  • 原文地址:https://www.cnblogs.com/Knight02/p/16092439.html
Copyright © 2020-2023  润新知