KMP 讲解

光隙褶皱
• 阅读 1322

KMP 讲解

这是 算法第四版 上的 KMP 算法。代码十分简洁,但是十分难懂。在我查了很多资料,想了很久之后,略懂一些。希望能记录下来,用于以后的复习。有的写得不周的地方,多多包涵。

public class KMP
{
    private String pat;
    private int[][] dfa;
    public KMP(String pat) {
        // 由模式字符串构造 DFA
        this.pat = pat;
        int M = pat.length();
        int R = 256;
        dfa = new int[R][M];
        dfa[pat.charAt(0)][0] = 1


        for (int X = 0, j = 1; j < M ; j++) {
            for (int c = 0; c < R; c++) {
                dfa[c][j] = dfa[c][X]       //复制匹配失败情况下的值
            }
            dfa[pat.charAt[j]][j] = j + 1   //设置匹配成功情况下的值 

            X = dfa[pat.charAt[j]][X]       //更新重启状态
        }
    }

    public int search(String txt) {
        // 在 txt 上模拟 DFA 的运行
        int i, j;
        N = txt.length();
        M = pat.length();


        for (int i = 0, j = 0; i < N && j < M; i++) {
            j = dfa[pat.charAt[i]][j];    
        }
            if (j == M) {
                return i - M;       // 找到匹配(到达模式字符串的结尾)
            }else {
                return N;          // 未找到匹配(到达文本字符串的结尾)
            }


    }
}

KMP 的核心思想是利用已经匹配过的信息来避免重复匹配。

下面看个例子

文本串:A A B A A B A A F A
模式串:A A B A A F
i, j分别代表文本串、模式串的下标

前 t-1+5 次匹配完,第 t-1+6 次匹配
   t         ⬇
···A A B A A B A A F A
···A A B A A F
             ⬆ 

此时 i 与 j 不一样。按照暴力的解法会变成下面这样,重新匹配。
     ⬇
···A A B A A B A A F A
  ···A A B A A F
     ⬆ 

DFA 构造

那我们可以看到 [t,i) 与 [t,j) 匹配一致,那我们能不能利用这个信息,做点事情,从而快速的移动到正确的位置,减少重复匹配。

由于文本串[t,i) 与 模式串[t,j) 匹配一致,那我们只要研究模式串[t, j) 部分。如果匹配失败,该回退到到哪里,才能保证匹配效率最大化。

也就是说,我们的研究目标变成了,以模式串[t, j) 部分为目标串,除去第一个位置外,找到最佳匹配位置。这样与目标串无关,是模式串自身与自身匹配。我们可以提前制定一张查询表,从而优化算法。

// dfa[256][pat.lenth]
// pat.charAt[0] 取得 模式串(pattern) 下标为 0 字符
dfa[pat.charAt[0]][0] = 1

for (int X = 0, j = 1; j < M ; j++) {
    
    for (int c = 0; c < 256; c++) {
        dfa[c][j] = dfa[c][X]       //复制匹配失败情况下的值
    }
    dfa[pat.charAt[j]][j] = j + 1   //设置匹配成功情况下的值 
    
    X = dfa[pat.charAt[j]][X]       //更新重启状态
}

由此我们再来看 KMP 的 dfa 的构造部分。j 为什么是从 1 开始就不难理解了。现在还有几个问题。X 代表什么? dfa 数组 代表着什么?

dfa 就是上文所说的查询表。给定两个输入,输出 模式串下标 该回退到哪里去。
输入:当前字符当前状态
输出:下个状态

接下来就是以 以模式串[t, j) ,除去第一个位置外,为目标串,也就是[t+1, j);以[t, j) 为模式串去匹配,去构造查询表
这里我们用到动态规划的思想。第 j+k 的查询表构造可以由 j+k-1 推导出来。动态规划初始化是 X=0, dfa[pat.charAt[0]][0] = 1

Next 数组构造

我们可以出,如果能回退到某个状态,那么子串拥有最大公共前后缀。上面 dfa 也是在寻找这个目标。具体可以参考 印度小哥讲解KMP算法
由此引出了子串最大公共前后缀。匹配过的模式串[t...j) 求得。利用子串最大公共前后缀,快速定位。

首先我们先来看 search 部分

我这里的 dfa数组 和视频里的 next 数组会有不同的地方,原理是一样的,后续也会看到如何降维从而构造出视频中的 next 数组。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
C++ 删除字符串的两种实现方式
C实现删除给定字符串的给定字符串思路主要有这么几种实现方式:1.KMP算法2.用STL的string的find,然后用erase3.用C的strstr找到字串位置,然后用strncpy写到新串中4.用boost库,用正则表达式测试过的完整代码:第一种方法:123456789101
Stella981 Stella981
3年前
KMP算法 左神 最传统 最详细的思路 JAVA
本文只是一个学习后的总结,可能会有错误,欢迎各位指出。任意转载。题目:给定一个字符串str1和一个字符串str2,在字符串str1中找出字符串str2出现的第一个位置(从0开始)。如果不存在,则返回1。str1aaaaabcabcstr2abcabcaa前段时间偶然接触到左神的算法讲解视频,大概
Stella981 Stella981
3年前
AC(Aho—Corasiek) 多模式匹配算法
简介:AC多模式匹配算法产生于1975年的贝尔实验室,最早使用于图书馆的书目查询程序中。该算法以有限状态自动机(FSA),以及KMP前缀算法为基础.(有说法:ac自动机是KMP的多串形式,是一个有限自动机)AC定义:AC有限自动机M是1个6元组:M(Q,∑,g,f,qo,F)其中:1、Q是有
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
搜索中常见数据结构与算法探究(二)
本文介绍了几个常见的匹配算法,通过算法过程和算法分析介绍了各个算法的优缺点和使用场景,并为后续的搜索文章做个铺垫;读者可以通过比较几种算法的差异,进一步了解匹配算法演进过程以及解决问题的场景;KMP算法和DoubleArrayTireTree是其中
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(