• KMP算法复习


    KMP算法

    在字符串匹配中,我们一般是BF算法,暴力破解。当然上完数据结构课之后,我们知道可以通过KMP进行优化。

    上数据结构这门课的时候,我没有好好听KMP,本篇文章参考程杰老师的《大话数据结构》中KMP算法一章节记录的笔记,可以的话请阅读原书中该章节,这里相当于原书的复述。

    这边引用书中的一句话:任何有难度的知识和技巧,都不是那么容易掌握的。我尽管已经朝着通俗易懂的方向努力,可有些数据结构,特别是经典算法,是几代科学家的智慧结晶,因此要掌握他们还是需要读者的全力投入。

    1.Next串

    关于Next串,根据Pattern串进行得出的回溯串。

    案例1

    1)Next数组,第一位Next[1]=0

    2)j=2的时候,j从0到j-1就只有字符“a“,那么给定一个1

    3)j=3的时候,j从0到j-1就只有字符“ab",那么给定一个1

    往后同理

    案例2

    1)Next数组,第一位Next[1]=0

    2)j=2的时候,同上,Next[2]=1

    3)j=3的时候,同上,Next[3]=1

    4)j=4的时候,同上,Next[4]=1

    5)j=5的时候,此时j由1到j-1的串是“abca”,前缀“a”,后缀“a”,推算k的值为2,则Next[5]=2

    6)j=6的时候,串为“abcab”,前缀“a”,后缀“a”,我们可以回溯到3,Next[6]=3

    我们可以根据经验得到如果前后缀一个字符相等,k的值是2,两个字符k的值是3,第n个就是n+1

    案例3

    1)Next数组,第一位Next[1]=0

    2)j=2的时候,同上,Next[2]=1

    3)j=3的时候,同上,Next[3]=1

    4)j=4的时候,串为“aba”,前缀“a”,后缀“a”,则Next[4]=2

    5)j=5的时候,串为“abab”,前缀“ab”,后缀“ab”,则Next[5]=3

    6)j=6的时候,串为“ababa”,前缀“aba”,后缀“aba”,则Next[6]=4

    7)j=7的时候,串为“ababaa”,只有“a”符合,则Next[7]=2

    8)j=8的时候,串为“ababaaa”,只有“a”符合,则Next[8]=2

    9)j=9的时候,串为“ababaaab”,只有”ab“符合,则Next[9]=3

    案例4

    1)Next数组,第一位Next[1]=0

    2)j=2的时候,同上,Next[2]=1

    3)j=3的时候,前缀为“aa”与后缀“aa”相同,Next[3]=2

    4)j=4的时候,前缀为“aaa”与后缀“aaa”相同,Next[4]=3

    .....

    2.朴素KMP

    通过这么多,我们可以来看一下代码,下面是朴素next数组和KMP,我们这边next是朴素KMP的求解方案

    void get_next(string T, int *next) { // T是匹配串
        int i = 1, j = 0;
        next[1] = 0;
        while(i < T[0]){// T[0]存储T的长度
            if(j == 0 || T[i] == T[j]) {
                i++;
                j++;
                next[i] = j;
            }else {
                j = next[j]; // 回溯
            }
        }
    }
    int KMP(string S, string T, int pos){
        int i = pos, j = 1;
        int next[255];
        get_next(T, next);
        while(i <= S[0] && j <= T[0]){
            if(j == 0 || S[i] == T[j]){
                i++;
                j++;
            }else j = next[j];
        }
        if(j > T[0]) return i - T[0];
        else return 0;
    }
    

    3.KMP算法改进

    朴素KMP存在一些缺陷。例如:S="aaaabcde",子串 T = "aaaaax"分别是012345,在开始,我们发现b与a不相等,因此j=next[5]=4,紧接着回溯3,直到0。所以我们在算法改进中进行优化操作,若与之前相等,则进行与之前相等操作。

    void get_next(string T, int *next) { // T是匹配串
        int i = 1, j = 0;
        next[1] = 0;
        while(i < T[0]){// T[0]存储T的长度
            if(j == 0 || T[i] == T[j]) {
                i++;
                j++;
                if(T[i] != T[j]) // 如果与前缀字符串不一样
                    next[i] = j; // 进行设置j为i
                else
                    next[i] = next[j]; // 否则进行赋值操作
            }else {
                j = next[j]; // 回溯
            }
        }
    }
    

    4.nextval数组改进推导

    案例

    1)开始nextval[1] = 0

    2)第二位字符b的nextval为1,二第一位就是“a”,不相等,维持原值

    3)第三位字符a的nextval为1,“a”与“a”相等,则变换为0

    4)第四位字符b的nextval为2,“b”与“b”相等,则变换为1

    5.总结

    其实只要细心耐心,KMP算法理解后也不是想象中那么麻烦,写起来还蛮方便的。但是在算法调试中,KMP确实不太好写,我们记忆住原理优先。

  • 相关阅读:
    xhr1.0和xhr2.0的区别
    Java10-堆和栈
    Java09-函数
    Java08-函数
    java基础7-流程控制3
    Java基础-流程控制2
    Java基础—流程控制1
    breadcrumbs面包屑是啥?
    Font test 字体大小测试用JS代码实现
    数据库密码要BS64才能登录
  • 原文地址:https://www.cnblogs.com/littlepage/p/12238844.html
Copyright © 2020-2023  润新知