看博客好多人都说这本来应该在数据结构里边学,奈何我一点印象都没有,估计当时老师也跳过了。然后今天从9点看到现在,好像才大致懂了
参考的这篇博客,真的很nice!!https://blog.csdn.net/v_JULY_v/article/details/7041827?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2
emmm,然后,我在这个算法上边遇到的第一个坎,竟然是分不清楚文本串(test)和模式串(pattern)??算法里边没说清楚next是对谁求得。这里明确一下:
目录
字符串的前缀和后缀:
暴力求解算法
KMP算法
1、求最大长度表
2、求next数组
3、完善KMP算法
Number Sequence
先理解字符串的前缀和后缀
举一个例子来看
字符串abcjkdabc
该字符串前缀与后缀相同的最大长度为3,即abc。
这一概念必须理解,在下边的next求解中会用到
#include
#include
#include
using namespace std;
int ViolentMatch(char* s,char* p){
int slen=strlen(s);
int plen=strlen(p);
int i=0,j=0;
while(i
即寻找最长前缀后缀
如果给定的模式串是:“ABCDABD”,从左至右遍历整个模式串,其各个子串的前缀后缀分别如下表格所示:
也就是说,原模式串子串对应的各个前缀后缀的公共元素的最大长度表为(下简称《最大长度表》):
那么·最大长度表有什么用呢?
最大长度表中每个元素long_length(j-1)=k的含义
总结一下我的理解:
前缀后缀和 t[i]!=p[j] 时 j 的移动是如何关联起来的?:
前缀必定从头(p[0])开始,后缀必定以最后一个字符(p[j-1])结束,如果前缀和后缀有长为k的公共元素,就是从 p[j-1] 往前的k个元素(p[j-k]~p[j-1]),与从字符串头开始的k个元素(p[0],p[1]……p[k-1])。此时如果 t[i]!=p[j] ,j往前移动 j-k 就可以到p[k],这样p[k]之前的k个元素就不用再去重新匹配了。而此处的 j-k 中的k,正是long_length(j-1)也是next(j)
这样就可以把next数组与j的移动联系起来啦
他和long_length的关系红字已经解释了
最大长度表整体右移一位得到next数组,开头补-1,可以当成一个特殊标记,表示不存在
已知next [0, ..., j],如何求出next [j + 1]呢?
对于P的前j+1个序列字符:
优化:
将
nextTable[j]=k;
变为
if(p[j]!=p[k]) {
nextTable[j]=k; //next[j + 1 ] = next [j] + 1 = k + 1
} else {
//p[j+1]=p[k+1]
//如果p[j]=p[next[j]], 应该继续递归, k=next[k]=next[next[k]]
nextTable[j]=next[k];
}
如果 p[j]==p[k]时,还要进行 nextTable[j]=k;,最后就会导致p[j]=p[nextTable[j]]。p[j]匹配失败时,与他相同的p[nextTable[j]]必然匹配失败,这一步是非常多余的,所以 当p[j]==p[k]时,不进行 nextTable[j]=k;而是继续递归,直到找到和 p[j]不同的p[nextTable[j]]才停止。
//char p[100]; 模式串
//m为p的长度
void GetNextTable(int m){ //m是模式串的长度
int j=0;
nextTable[0]=-1; //初始值赋值-1
int k=-1;
while(j
//char s[100] 文本串 长为n
//char p[100] 模式串 长为m
int KMP(int n,int m){
GetNextTable(m);
int i=0;
int j=0;
while(i
最后是一个KMP模板题,趁热打铁,练一练
HDU - 1711
#include
using namespace std;
int s[1000005];
int p[10005];
int nextTable[10005];
void GetNextTable(int m){ //m是模式串的长度
int j=0;
nextTable[0]=-1; //初始值赋值-1
int k=-1;
while(j