1. 简介
KMP 算法是一种优秀的字符串模式匹配算法,相对于暴力匹配方法来说,其改进在于:每当一趟匹配过程出现字符比较不相等时,不需回溯主串的 i 指针,而是利用已经得到的「部分匹配」的结果将模式串向右「滑动」尽可能远的一段距离后(即回溯模式串的 j 指针),继续进行比较。
2. 实现
- 假设从主串第 pos 个字符开始和模式串匹配,此时主串中第 i(pos≤i) 个字符和模式串的第 j 个字符比较,且 si=pj,说明从主串第 pos 个字符开始匹配无法找到模式串子串,因此需要将 pos 向右「滑动」(即增大主串开始匹配字符的位置)。
- 而增大主串开始匹配字符的位置可以通过将模式串向右「滑动」实现。如果此时存在最大的 k 使得 p0⋯pk−1=pj−k⋯pj−1 且 pk=pj,则可以将模式串向右「滑动」使得模式串第 k 个字符对应到第 j 个字符,即模式串整体向右滑动了 j−k 个字符。
- 设 k=max{u∣0<u<j⋀p0⋯pu−1=pj−u⋯pj−1},则失配数组的计算公式如下:
next[j]=⎩⎪⎪⎨⎪⎪⎧−1knext[k]j=0if pk=pjif pk=pj
计算失配数组时间复杂度 O(m),主串与模式串匹配时间复杂度 O(n),故 KMP 算法总的时间复杂度为 O(n+m) 。
3. 模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| #include <bits/stdc++.h> using namespace std;
#ifndef _KMP_ #define _KMP_ #define ll int #define MAXN 1000005 #define MAXM 1000005
struct KMP { ll next[MAXM]; vector <ll> match; KMP() {} void getNext(char *pattern, ll m) { next[0] = -1; ll i = 0, j = -1; while(i < m) { if(!(~j) || pattern[i] == pattern[j]) { ++i, ++j; if(pattern[i] != pattern[j]) next[i] = j; else next[i] = next[j]; } else { j = next[j]; } } } ll getIndex(ll pos, char *main, ll n, char *pattern, ll m) { ll i = pos, j = 0; while(i < n && j < m) { if(!(~j) || main[i] == pattern[j]) { ++i, ++j; } else { j = next[j]; } } if(j < m) { return -1; } return i - m; } void getIndexs(char *main, ll n, char *pattern, ll m) { ll i = 0, j = 0; while(i < n) { if(!(~j) || main[i] == pattern[j]) { ++i, ++j; if(j == m) { j = next[j]; match.push_back(i-m); } } else { j = next[j]; } } } }; #endif
|