1.什么是KMP算法
解决字符串匹配问题;看文本串是否出现过模式串;
文本串:aabaabaaf;
模式串:aabaaf;
暴力解法:两层for循环,时间复杂度:O(m*n) m n分别是长度;
kmp解决:
f和b不匹配后(竖线),跳到模式串第一个b重新开始匹配;为啥跳b看下面
前缀表:b的前面是aa,后面也是aa,所以遇到不匹配的时候,就找前面最长前后缀;
aabaaf
前缀:包含首字母,不包含尾字母的所有子串;a aa aab aaba aabaa aabaaf;
后缀:包含尾字母,不包含首字母的所有子串;af aaf baaf abaaf
最长相等前后缀:a 0 aa 1 aab 0 aaba 1 aabaa 2 aabaaf 0
前缀表: 0 1 0 1 2 0 (上面数字) 2意味着有一个后缀aa ,前面有一个前缀aa。所以匹配从前缀的后面开始匹配,就是从b重新开始匹配;
next数组 或者prefix前缀表;
2.代码
next数组形式: 遇到冲突向前回退
左移一: -1 0 1 0 1 2;
整体减1 -1 0 -1 1 -1;
void getNext(int *next,char *s){
//初始化i 后缀末尾 j前缀末尾,也代表i 包括i之前这个子串的最长相等前后缀的长度
int j = 0;
int next[0] = 0;
int len = strlen(s);
for(int i = 1; i < len; i++) {
//前后缀不同
while(s[i] != s[j] && j > 0) {
j = next[j-1]; // j 回退
}
// 前后缀相同
if(s[i] == s[j]){
j++;
// 更新next值
next[i] = j;
}
}
}
题目描述
//前缀表不减一版本
void getNext(int* next, char* s) {
//初始化 next
int j = 0;
next[0] = j;
for (int i = 1; i < strlen(s); i++) { //注意 i 从 1 开始
//若前后缀不相同
while (j > 0 && s[i] != s[j]) {
//则向前回退
j = next[j - 1];
}
//若前后缀相同
if (s[i] == s[j]) {
//i 和 j 同时向后移动(i 的增加在 for 循环里)
j++;
}
//将 j(前缀的长度)赋值给 next[i]
next[i] = j;
}
}
int strStr(char * haystack, char * needle){
int len1 = strlen(haystack);
int len2 = strlen(needle);
//当 needle 为空字符串时,返回 0
if (len2 == 0) {
return 0;
}
//构建 next 数组
int* next = malloc(sizeof(int) * len2);
getNext(next, needle);
//next 记录的起始位置为 0,所以这里也从 0 开始
int j = 0;
for (int i = 0; i < len1; i++) { //注意匹配时 i 从 0 开始
//若不匹配
while (j > 0 && haystack[i] != needle[j]) {
//j 退回到之前匹配的位置
j = next[j - 1];
}
//若匹配
if (haystack[i] == needle[j]) {
//i 和 j 同时向后移动(i 的增加在 for 循环里)
j++;
}
//当 j 等于 needle 的长度时,说明字符串 haystack 里出现了字符串 needle
if (j == len2) {
//返回 needle 字符串出现的第一个位置
return (i - len2 + 1);
}
}
//若未找到则说明不存在,返回 -1
return -1;
}
题目描述
void CalcNext(char *p,int *next)
{
next[0]=-1;
int nlen = strlen(p);
int k = -1;
int j = 0;
while (j < nlen) {
if (k ==-1 || p[j] == p[k]) {
++k;
++j;
next[j] = k;
}
else
k = next[k];
}
}
bool repeatedSubstringPattern(char * s){
int length = strlen(s);
int *next=(int *)malloc(sizeof(int)*(length+1));
CalcNext(s,next);
int k = next[length];
int p = length-k;
if(length%p == 0 && length != p)
return true;
return false;
}