日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

KMPEXKMP学习笔记

發布時間:2024/1/17 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 KMPEXKMP学习笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

字符串匹配算法KMP

KMP是啥

一種基礎的字符串匹配算法,是學習字符串算法的基礎

很多人都是以這個算法為起點開始學習字符串的

KMP的作用

求出模式串在文本串里出現了多少次,以及在哪里出現過

KMP的實現

暴力

假如直接暴力匹配的話,復雜度\(O(nm)\)(n是模式串長度,m是文本串長度)

明顯T飛

于是我們就有了KMP算法

核心部分

先上定義部分:

int kmp[2000001];//kmp中的指針 char a[2000001],b[2000001];//a是文本串,b是模式串

然后我們現在來看一看什么是kmp里面的kmp數組。

  • kmp失配指針

這個失配指針就是上面的kmp數組了

這個kmp是什么意思呢?這個kmp[i]代表的是,在[1..i]這個子串中,前綴與后綴的最長長度

  • kmp第一步:自配
for(int i=2;i<=l2;++i){//l2是模式串長度while(j&&b[i]!=b[j+1]){//一會兒解釋j=kmp[j];}if(b[i]==b[j+1])j++;kmp[i]=j;}

首先定義前綴i代表子串[1..i],后綴i代表子串[j..len]

這其中的\(while(j&&b[i]!=b[j+1])\)是怎么回事兒呢?

首先我們要知道,j就是前綴i-1的前綴與后綴的最長相同長度

那么我們首先看一看目前走到的第i位與第j+1位相不相同

假如相同,那么前綴j+1就與后綴[i-j..i]相同了

假如不同,那么我們跳到下一個相同的地方。

然后不斷地沿著kmp跳,直到跳到相同的地方。假如沒有相同的,那這個kmp[i]就為0了。

如下圖所示:

那么這里的i為什么不能取1呢?

大家可以自己試一試,如果取1的話就死循環了

  • kmp第二步 在原串中匹配
for(int i=1;i<=l1;++i){//l1是文本串長度while(j&&a[i]!=b[j+1]){j=kmp[j];}if(a[i]==b[j+1])j++;if(j==l2){printf("%d\n",i-l2+1);j=kmp[j];}}

有關于\(while(j&&a[i]!=b[j+1])\),這就是說,我們現在匹配到的第i位與b中的第j+1位不符合的話,

我們就找到前綴j+1的前綴與后綴的最長相同長度,然后從已經匹配好的前綴跳到相同的后綴上

大概就是這幅圖:

kmp到這里就結束啦~

  • 完整代碼(洛谷P3375 【模板】KMP字符串匹配)
#include<bits/stdc++.h> using namespace std; int kmp[2000001]; char a[2000001],b[2000001]; int main(){scanf("%s",a+1);scanf("%s",b+1);int l1=strlen(a+1),l2=strlen(b+1);int j=0;for(int i=2;i<=l2;++i){while(j&&b[i]!=b[j+1]){j=kmp[j];}if(b[i]==b[j+1])j++;kmp[i]=j;}j=0;for(int i=1;i<=l1;++i){while(j&&a[i]!=b[j+1]){j=kmp[j];}if(a[i]==b[j+1])j++;if(j==l2){printf("%d\n",i-l2+1);j=kmp[j];}}for(int i=1;i<=l2;++i)printf("%d ",kmp[i]);//題目要求輸出kmp數組putchar('\n'); }
  • 復雜度

時間復雜度是\(O(n+m)\)的(這不比樸素算法快多了?)

跑起來飛快(huaji)

EXKMP(擴展KMP)

簡介

這個算法用來求一個串的每個后綴與另一個串的\(LCP\),即最長公共前綴

然而似乎與kmp沒有什么關系

有關于這個算法,我當時并沒有怎么學

而且貌似是一個邊緣算法,不怎么會考

所以貼個模板跑路吧

#include<bits/stdc++.h> using namespace std; int nxt[2000001]; int ext[2000001]; void pre(char s[]){int m=strlen(s);int j=0,p=0;nxt[0]=m;for(int i=1;i<m;++i){if(i>=p||i+nxt[i-j]>=p){if(i>=p)p=i;while(p<m&&s[p]==s[p-i])p++;nxt[i]=p-i;j=i;}else nxt[i]=nxt[i-j];}//for(int i=0;i<m;++i)printf("%d ",nxt[i]);//putchar('\n'); } void getext(char s[],char t[]){int n=strlen(s);int m=strlen(t);int j=0,p=0;pre(t);for(int i=0;i<n;++i){if(i>=p||i+nxt[i-j]>=p){if(i>=p)p=i;while(p<n&&p-i<m&&s[p]==t[p-i])p++;ext[i]=p-i;j=i;}else ext[i]=nxt[i-j];//cout<<ext[i]<<" ";} } char s[2000001],t[2000001]; int main(){scanf("%s%s",s,t);getext(s,t);int q;scanf("%d",&q);for(int i=1;i<=q;++i){int tmp;scanf("%d",&tmp);printf("%d\n",ext[tmp-1]);} }

轉載于:https://www.cnblogs.com/youddjxd/p/10846486.html

總結

以上是生活随笔為你收集整理的KMPEXKMP学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。