KMP
KMP
首先有暴力算法:
int findPos(char S[], char T[]) {
int lens = strlen(S), lent = strlen(T), i = 0, j = 0;
while(i<lens && j<lent) {
if (S[i] == T[j])
i++,j++;
else
i = i -j + 1,j = 0; // i, j均移动
}
return (j >= lent ? i - lent : -1);
}
然后对暴力算法进行优化:
只移动j,而不移动i。
对于j的移动,j应该如何移动?
当前的
由此,我们想知道,对于每一次
对于nxt数组,求nxt[j]也就是对t[0~j-1]的最长相同前后缀的长度,那么问题就是,如何快速地得到最长相同前后缀的长度。
下面求nxt数组:
考虑我们已经得到了nxt[0~i],要求nxt[i+1]。
根据定义,nxt[i+1]就是t[0~i]的最长相同前后缀的长度。有下图:
求nxt代码:
void CalcNext(char T[],int next[]) {
next[0] = -1, next[1] = 0;
for (int i = 1;i < (int)(strlen(T) - 1);i++) {
int k = next[i];
while (k != -1 && T[i] != T[k])
k = next[k];
next[i + 1] = k + 1;
}
}
由此,我们已经得到了KMP:
int findPos_kmp(char S[], char T[], int next[]) {
int lens = strlen(S), lent = strlen(T), i = 0, j = 0;
while(i<lens && j<lent) {
if(j == -1 || S[i] == T[j])
i++,j++;
else
j = next[j]; // 只移动j,而不移动i.
}
return (j >= lent ? i - lent : -1);
}
可选优化:
我们知道,对于最大相同前后缀的后缀的后一个字符,如果匹配失败,显然会找到前缀的后一个字符,再进行判断,如果前缀的后一个字符和后缀的后一个字符相等的话,那从后缀的后一个字符到前缀的后一个字符的操作显然无意义,肯定不相等。于是,我们可以判断后缀的后一个字符和前缀的后一个字符是否相等,如果相等,就让后缀的后一个字符的nxt等于前缀的后一个字符的nxt。
void CalcNextVal(char T[],int next[],int nextVal[]) {
int len = strlen(T);
for (int i = 0;i < len;i++)
nextVal[i] = next[i];
for (int i = 1;i < len;i++) {
int k = nextVal[i]; // 前缀的后一个字符。
if (T[i] == T[k])
nextVal[i] = nextVal[k]; // 后缀的后一个字符的nxt等于前缀的后一个字符的nxt
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App