字符串匹配算法之KMP算法(图例详解)
1.字符串匹配算法及暴力算法
在字符串匹配算法之暴力做法(朴素算法)我这篇文章已经详细介绍了字符串匹配算法以及它的暴力算法。现在简单复习一下。
1.1 简介
字符串匹配算法又称模式匹配(pattern matching)。该问题可以概括为「给定字符串S
和T
,在主串S
中寻找子串T
」。字符T
称为模式串 (pattern)。
1.2 示例题目
还是使用来自leetcode 28. 实现 strStr()的这道题。
实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
示例 1:输入: haystack = "hello", needle = "ll" 输出: 2
2.KMP算法(Knuth-Morris-Pratt algorith)
2.1 朴素算法的缺点
在介绍KMP算法之前,我们先回顾一下朴素算法的缺点,有助于我们更好地理解KMP算法。
先看一下这个例子:
txt[] = “AAAAAAAAAAAAAAAAAB”
pat[] = “AAAAB”
如果是朴素算法一个一个对比的话,pat[]一个一个地右移。
第一步:
第二步:
第三步:
\
而其实我们在第一步时就已经匹配过中间的3个A
了。
这就是朴素算法重复的部分,而KMP算法就将重复的部分跳过了。
2.2 KMP算法
KMP算法是如何跳过这一部分的,我们首先需要了解前缀函数。
2.2.1 KMP算法中的前缀算法
2.2.1.1 前缀函数pi的定义
给定一个长度为n
的字符串s
,其 前缀函数 被定义为一个长度为n
的数组p[]
。 其中p[i]
的定义是:
- 如果子串
s[0...i]
有一对相等的真前缀与真后缀:s[0...k-1]
和s[i-(k-1)...i]
,那么p[i]
就是这个相等的真前缀(或者真后缀,因为它们相等子串的长度,也就是p[i] = k
; - 如果不止有一对相等的,那么
p[i]
就是其中最长的那一对的长度; - 如果没有相等的,那么
s[i]=0
。
简单来说p[i]
就是子串s[0...i]
最长的相等的真前缀与真后缀的长度。
用数学语言描述如下:
p [ i ] = m a