一、简介
Knuth-Morris-Pratt字符串搜索算法(或KMP 算法)通过观察在发生不匹配时,单词本身包含足够的信息来搜索W主要“文本字符串”中出现的“单词”S来确定下
一个匹配的开始位置,从而绕过对先前匹配字符的重新检查。
该算法由James H. Morris构思,并由Donald Knuth “几周后”从自动机理论中独立发现。Morris 和Vaughan Pratt在 1970 年发表了技术报告。
三人也在 1977 年联合发表了该算法。独立地,1969 年,Matiyasevich [4] [5]发现了类似的算法,由二维图灵机编码,同时研究二进制字母表上的字符串
模式匹配识别问题。这是第一个用于字符串匹配的线性时间算法;
两个字符串匹配时,当两个字符相等则一起往后移动;
当出现不匹配时,就查找next数组,跳跃到最大前缀的位置继续匹配;
当跳跃的情况不满足子串匹配时,则主串的索引往后挪动;
二、图解
三、代码
#include <iostream>
#include <tuple>
#include <vector>
#include <string>
using namespace std;
string s1, s2;
/**
* 获取next数组
* */
vector<int> getNext(const string& s) {
vector<int> vc;
if(s.size() == 1) return vc;
vc.resize(s.size());
vc[0] = -1;
vc[1] = 0;
int i = 2;
int cnt = 0;
/* 生成数组 */
while (i < s.size()) {
if(s[i-1] == s[cnt]) vc[i++] = ++cnt;
else if(cnt > 0) cnt = vc[cnt];
else vc[i++] = 0;
}
return vc;
}
/** 字符串比较 */
int Kmp(const string& s, const string& subS) {
if(s.empty() || subS.empty() || s.size() < subS.size()) return -1;
vector<int> str_next = getNext(subS);
if (str_next.empty()) return -1;
int i=0, j=0;
while (i < s.size() && j < subS.size()) {
if(s[i] == subS[j]) i++, j++; // 当两个字符相等则往后移动
else if(str_next[j] == -1) i++; // 当数组不能往前跳跃即没有相同前缀,则主串后移
else j = str_next[j]; // 当没有匹配时,子串往前跳跃到相同前缀开始匹配
}
return j == subS.size() ? i - j : -1;
}
参考:
一周刷爆LeetCode,算法大神左神(左程云)耗时100天打造算法与数据结构基础到高级全家桶教程,直击BTAJ等一线大厂必问算法面试题真题详解