KMP算法概要

前言
经典空间换时间算法 看了贼久才看懂 网上的博客文章有很多 但是基本都很复杂 从头到尾说一遍我是真的没那精力和耐心 因此这篇只说一下最核心的几个问题
写的更多是我的思考的过程 希望能对大家有帮助
请结合jlu数据结构课本食用
kmp这三个老家伙一个比一个顶
网上的很多文章中对于失败函数的定义并不相同 但是大体思路一致 请注意本文f()的含义

kmp算法

为什么会有kmp算法?

我们知道最简单的字符串匹配方法是暴力破解,即将模式串与主串从第一位开始匹配,若不成功则让模式串从主串第二位开始匹配,一直到模式串末尾与主串末尾重合为止。
不用想也知道这种算法虽然简单但是极其耗时
为什么?
因为在对失败位置之前的n个字符进行匹配的过程中我们已经 获得了前n个字符的信息 而不对这些信息进行判断直接从初始位置的下一位开始匹配是对已知信息的一种浪费
如何改进?

//举个栗子
主串:  abaaabab(s)
模式串:abab(p)

这时我们已经知道p[0]=p[2] p[1]=p[3]
开始第一次匹配 结果为 s[0]=p[0] s[1]=p[1] s[2]=p[2] s[3]!=p[3]
这时按照爆破算法第二次应当逐一匹配

主串:   abaaabab(s)
模式串: _abab(p)

即比较s[1]与p[0] s[2]与p[1] s[3]与p[2] s[4]与p[3]
而我们第一次匹配已经知道
s[1]=p[1] s[2]=p[2]
所以第二次匹配如果想要成功
起码要满足前提 p[1]=p[0] 且p[2]=p[1]
但是模式串p显然不满足这个条件 所以第二次匹配可以直接跳过
这样一来 通过这次判断 我们将问题转化到了p字符串本身 减少了s与p的比较次数 从而降低了时间复杂度 而如果我们多次进行这样的判断 省去中间所有没有意义的匹配过程 那不就是对算法进行了优化吗?

kmp的实现思路

假定p串长度为m
对于通常情况来说假设某一次匹配某次匹配后,stst+1…st+j与p0p1…pj匹配而st+j+1与pj+1不等,匹配失败
通过之前的分析,我们知道此时要比较p本身 如果p0…pj-1不等于p1…pj的话爆破算法的下一步匹配就可以去掉
然后继续对p串进行移位 直到找到一个k 使得p0…pK=pj-k…pj 这时才满足了判断的前提 同时根据已经匹配上的部分可以知道
st+j-k…st+j=pj-k…pj=p0…pk 也就是说p串的前k位已经可以匹配s串的对应位置了那么只需要对p串中剩余的其他位与s串后面的位置进行比较即可
即比较st+j+1…st+j+m-k与pk+1…pm是否相等
推广一下 kmp的思路即为 匹配失败后通过对模式串本身进行对比计算出模式串与主串已经匹配了的k位 然后从模式串的下一位开始继续进行下一次匹配
而在上面的过程中 最核心的问题就是计算k的值 k值关系到匹配失败后下一次匹配的回溯位置 而课本上引入了失败函数 f(i); 其含义为 从p[0]到p[i]的字符串中前缀和后缀的最长重复长度-1

//举个栗子
p:    abcab
f(i): -1 -
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值