KMP算法基本流程
核心思路:寻找回溯位置
其实便是众所皆知的使用next数组,通过next数组的保存p前后缀的交集的最大长度
例如:给定一个Pattern:abedabexa
默认index为0的位置的next值为0,由于下标i和j所对应的字符不同,i保存不变,j下标next值为0,j向后移一位
由于下标i和j所对应的字符不同,i保存不变,j下标next值为0,j向后移一位
由于下标i和j所对应的字符不同,i保存不变,j下标next值为0,j向后移一位
下标i和j对应字符相同,i,j同时向后移动一位,j下标的next值为i下标的next值+1
注意:下标j-1对应的next值为1,说明了,j下标前已有前缀和后缀重复的字符串,其长度为1,那么j的next值则赋为(j-1)下标的next值+1
重复上述思路
到了这里,出现了字符不匹配,那么该怎么办呢?
解决:下标i移至下标(i-1)所对应的next值,并继续匹配i和j所对应的字符
由于i与j所对应字符不相同,且i无法再继续向前移动,那么j的next值则赋为i的next值
由于下标i已经为0
- 若i与j所对应字符不匹配,i无法继续向前移动只能将j对于next值赋为i的next值
- 若i与j所对应字符相匹配,则j对应的next值则赋为i的next值+ 1
j下标超出数组最大下标,完成next数组的构造
代码实现
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void GetNextArr(char* pattern, int* next, int next_len) {
next[0] = 0;
int i = 0;
int j = 1;
bool isRet = false;
while (j < next_len) {
if (pattern[i] == pattern[j]) {
if (isRet) {
next[j] = next[i] + 1;
isRet = false;
}
else {
next[j] = next[j - 1] + 1;
}
i++; j++;
}
else {
//回退
while (i > 0) {
i = next[i - 1];
if (pattern[i] == pattern[j]) {
break;
}
isRet = true;
}
//不可回退
if (i == 0) {
if (pattern[i] != pattern[j]) {
next[j++] = 0;//next[j++] = next[i];
}
else {
next[j++] = 1;
}
isRet = false;
}
}
}
}
bool KMP(char* text, char* pattern) {
if (!text || !pattern) return false;
int t_len = strlen(text);
int p_len = strlen(pattern);
int* next = new int[p_len];
GetNextArr(pattern, next, p_len);
int i = 0, j = 0;
while (i < t_len && j < p_len) {
if (text[i] == pattern[j]) {
i++; j++;
}
else if (j == 0) {
i++;
}
else {
j = next[j - 1];
}
}
if (j == p_len) {
return true;
}
delete[] next;
return false;
}
来源:CSDN
作者:君梦如烟2020
链接:https://blog.csdn.net/u012342808/article/details/104470415