KMP算法的一些细节
来源:互联网 发布:网贷安卓源码 编辑:程序博客网 时间:2024/06/03 20:22
此篇记录了我学习KMP算法时的迷惑和解决过程
(本篇适合学习KMP算法之后,对算法尚有些迷惑的朋友,欢迎大家批判)
1、第一个疑问:KMP算法是否一定能求出正确的首个匹配下标(匹配字符串的第一个字符的下标)
因为KMP算法不像暴力求解算法一样是一个一个字符行进的,有点类似跳跃的行进,跳过了不需要匹配的字符,我产生了一个疑问,在行进的过程中是否会遗漏本可以匹配的字符串,导致得到的匹配下标不是首个匹配下标,而是第二或第三第四个
反证,假设不能。即存在一个被忽略的更小的下标。
k
A B A B A A B........
A B A A B ------>黄色为匹配失败处
i h k (i是假设的,h为最长前缀开始处)
A B A B A A B........
A B A A B ------>不同于暴力求解一位一位右移,而是类似“跳跃”。红色处为最长前缀,黄色处继续匹配
假设我们会遗漏一个“更小的匹配下标i”,使得文本txt[i]~txt[i+length] (length为模式串长度)与模式串pat[0]~pat[length]匹配,那么txt[i]~txt[k]一定是比我们当前的“最长前缀”txt[h]~txt[k]更长的前缀,则与“next数组保存的是最长前缀”相矛盾,故不可能存在更长的前缀,即i不存在。
证得:我们不会遗漏一个更小的匹配下标
2、next数组的求法
01234k678910 j j+1ABGABBABGABGH-100012012345? next[k] = 2
第一行为模式串下标,第二行为模式串,第三行为next值
我们现在要求next[j+1],我们容易知道,如果pat[k] == pat[j],使得pat[0]~pat[k] == pat[j-k]~pat[j]的话,
那么next[j+1] = next[j]+1
那要是不等于呢?即pat[k] != pat[j]
通过学习,我们知道,要比较pat[next[k]]和pat[j],如果pat[next[k]] == pat[j],则next[j+1] = next[k] + 1
问题就是,为什么是比较pat[next[k]]和pat[j] ,为什么是next[k]??????
看上图,黄色标记处pat[k(5)] = B和pat[j(11)] = G匹配失败,而next[k] = 2,pat[next[k]] = pat[2] = G,最长前缀长度变成了3,即A B G,是可以匹配的最长前缀(pat[0~2] == pat[9~j])
事实上,我们可以证明这一事实的正确性
因为匹配失败,那么我们要寻找的最长前缀肯定是一个比A B G A B(0~k-1)更短的前缀
而且这个更短的前缀,一定是包含在A B G A B(0~k-1)里(因为必须从第一个字符开始,且长度更短)
仔细思考,我们得出这样一个结论:
我们假设这个最长前缀存在(pat[j+1]前的最长匹配前缀),设为str
则str - pat[j] 的长度一定等于next[k]
看下图
该图中str = ABG, pat[j] = G
(一定要注意观察和思考下面的三个红色A B)
next[k] = 2
我们先不管pat[j],先寻找pat[j]前长度稍短于k的前缀(实际上这个稍短前缀的长度就是next[k]),然后再加上pat[j]得到新前缀,得到next[j+1] = next[k]+1。上例中这个稍短前缀就是AB,pat[j] = G。
为什么稍短前缀的长度就是next[k]?
因为pat[0] ~ pat[k-1]和pat[j-k]~pat[j-1]都是一样的(已经匹配过)
那么str - pat[j]必然和pat[k]前的子串一模一样(而且这两个串都一定等于一个前缀,在上例中就是AB)
由于我们要使得str - pat[j]最长,那这个最长的长度一定就是next[k]
最后,我们再判断是否pat[next[k]] = pat[j],如果等于,则得到next[j+1] = next[k] + 1 (AB + G)
否则,再继续递归寻找,下一步判断pat[next[next]]。。。。道理同上
- KMP算法的一些细节
- KMP算法:KMP算法个人理解+next数组细节处理的方法
- KMP 算法 自己的一些理解
- KMP模式匹配算法的一些理解
- 【2】KMP算法的一些理解问题
- KMP算法的一些误区及其优化
- 运用kmp算法解决的一些问题的简单题解
- 对kmp算法next数组的一些简单理解
- KMP算法求next数组的一些理解
- document_getElementById的一些细节
- JS的一些细节
- 一些简单的细节
- dll的一些细节
- C++的一些细节
- Servlet的一些细节
- Servlet的一些细节
- Servlet的一些细节
- Servlet的一些细节
- 软件工程了解
- 为什么要写博文?
- hive shell常用操作
- 彩色宝石项链C/C++解决
- 1. Two Sum
- KMP算法的一些细节
- JAVA序列化和反序列化的常见格式
- 《.NET 设计规范》第 9 章:常用的设计模式
- 【LeetCode】404. Sum of Left Leaves
- 集合类源码简单阅读(一)(ArrayList)
- MYSQL数据库间同步数据
- 坐标系变换数学基础
- 服务器客户端
- web访问的原理