KMP算法详解


详解:https://www.cnblogs.com/yjiyjige/p/3263858.html
https://blog.csdn.net/lee18254290736/article/details/77278769

字符串匹配的暴力方法与KMP的比较:

遇到以下情况时:

image.png
  1. 暴力方法把匹配的指针下移一位


    image.png
  2. KMP根据next数组跳过不需要遍历的部分:


    image.png

KMP的思想:

利用已经部分匹配这个有效信息,保持i指针不回溯,通过修改j指针,让模式串尽量地移动到有效的位置。

推理:

当T[i] != P[j]时
有T[i-j ~ i-1] == P[0 ~ j-1]
由P[0 ~ k-1] == P[j-k ~ j-1]
必然:T[i-k ~ i-1] == P[0 ~ k-1]

PS:为什么是i-k~i-1而不是i-k~i-x(x>1)?

因为如果是i-k~i-x的话说明就算j移到i-k还是无法匹配i-x~i-1这段字符串,所以必须以i-k开头i-1结尾。
image.png

next数组的含义:(next数组由匹配串ABCE自己生成)

当j位失配时,j需要回退到的地方,即next[j]。(j是pattern对应的指针)

next数组如何定义?又如何判断要跳过多少元素呢?

Next[0]==Next[1]== -1是默认值,但是在处理中第一位pattern[0]不匹配时要i++,其他只需要j=0即可。如果pattern[i]不匹配,则将j指针指向Next[i]=2,即j=Next[];


Next数组的写法:

// 当第n位不匹配时怎么跳。
void getnext(char pattern[]){
  int i=0,j=0,k=0;
  // 事先约定好的两位
  Next[0]=-1;
  // 第一位不跳,-1位不存在匹配的情况。
  Next[1]=-1;
  // 第二位不匹配,但第一位匹配,移动一位。比如ab与ac不匹配,肯定将i移动到b后面。

  for(i=2;i<strlen(pattern);i++){
    // 从pattern[2]开始不匹配时
    Next[i]=-1;
    for(j=i-2;j>=0;j--){
      // j的结束位置从[0,i-2],开始位置默认0的贴前字符串
      for(k=0;k<=j;k++){
        // [0,i-2]的贴后字符串
        //cout<<"i:"<<i<<"  k:"<<k<<"  "<<pattern[k]<<"  j:"<<j<<"  "<<pattern[i-1-j+k]<<endl;
        if(pattern[k]==pattern[i-1-j+k]){

        }
        else{
          break;
        }
      }
      if(k==j+1){
        Next[i]=j+1;
        // 最长的匹配子串长度(0-j),所以长度是j+1
        break;
      }
    }
  }
}
image.png

在k的循环体里面:


image.png

Next数组基础上的kmp:

void kmp(char text[],char pattern[]){
  int i=0,j=0;
  int t=strlen(text);
  int p=strlen(pattern);
  bool pass=false;
  while(i<t){
    // 只要看text的指针有没有越界即可,反正pattern的指针j越界就会跳出循环匹配成功
    //cout<<i<<"   "<<j<<"  "<<Next[j]<<endl;
    if(text[i]==pattern[j]){
      i++;
      j++;
    }
    else{
      if(Next[j]==-1&&j==0){
        // 如果没有找到串内重复的串,只需要将pattern的指针指向开头就好。
        // ab与ac如果把j=0,会陷入死循环。
        i++;
      }
      else if(Next[j]==-1){
        j=0;
      }
      else{
        // 如果匹配失败,将j指针指向Next[j]对应的地址。
        j=(Next[j]);
      }
    }
    if(j==strlen(pattern)){
      pass=true;
      cout<<"\nmatch: ["<<i-strlen(pattern)<<","<<i-1<<"]"<<endl;
      show(text,i-strlen(pattern),i-1);
    }
  }
  if(!pass)cout<<"\nNo matching"<<endl;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容