一. 背景
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。
题目链接-LeetCode
对于上述问题,最简单直接的方法是直接对两个字符串进行遍历,看是否能够匹配,如果两个字符串输入规模分别为 m m m 和 n n n,那么算法的时间复杂度为 O ( m × n ) O(m \times n) O(m×n),为了降低该操作的时间开销,我们可以使用KMP算法。
二. KMP算法介绍
KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出,其思想是利用匹配过程中的信息,减少字符串匹配次数。
三. 相关概念
- 前缀:以第一个字符开头,并且不包含最后一个字符的连续子串。
- 后缀:以最后一个字符结尾,并且不包含第一个字符的连续子串。
- 公共前后缀:字符串内部有很多前缀和后缀,如果某个前缀和后缀相同,我们称这个前缀(后缀)为公共前后缀。
- 最长公共前后缀:长度最长的公共前后缀。
- 模式串:被匹配的字符串。
- 文本串:待选的字符串。
我们下面的介绍就基于上述概念进行展开。
四. 算法步骤
1. 构造模式串的next数组
首先我们给出 next[i] 的物理含义:前 i+1 个字符构成的字符串最长公共前后缀的长度,我们下面的描述都基于这个含义。
需要说明的是,实际编码时为了方便会在上述长度的基础上减一,在描述原理时我们不考虑这个问题。
举例:模式串 abdaabdaaabd,j为最长公共前后缀的长度,cs为公共前后缀。
i | s | j | cs |
---|---|---|---|
0 | a | 0 | – |
1 | ab | 0 | – |
2 | abd | 0 | – |
3 | abda | 1 | a |
4 | abdaa | 1 | a |
5 | abdaab | 2 | ab |
6 | abdaabd | 3 | abd |
7 | abdaabda | 4 | abda |
8 | abdaabdaa | 5 | abdaa |
9 | abdaabdaaa | 0 | – |
10</ |