亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C > 正文

KMP算法最淺顯理解(小白教程)

2020-01-26 11:44:09
字體:
來源:轉載
供稿:網友

說明

KMP算法看懂了覺得特別簡單,思路很簡單,看不懂之前,查各種資料,看的稀里糊涂,即使網上最簡單的解釋,依然看的稀里糊涂。
我花了半天時間,爭取用最短的篇幅大致搞明白這玩意到底是啥。
這里不扯概念,只講算法過程和代碼理解:

KMP算法求解什么類型問題

字符串匹配。給你兩個字符串,尋找其中一個字符串是否包含另一個字符串,如果包含,返回包含的起始位置。
如下面兩個字符串:

char *str = "bacbababadababacambabacaddababacasdsd";char *ptr = "ababaca";

str有兩處包含ptr
分別在str的下標10,26處包含ptr。

“bacbababadababacambabacaddababacasdsd”;/

這里寫圖片描述

問題類型很簡單,下面直接介紹算法

算法說明

一般匹配字符串時,我們從目標字符串str(假設長度為n)的第一個下標選取和ptr長度(長度為m)一樣的子字符串進行比較,如果一樣,就返回開始處的下標值,不一樣,選取str下一個下標,同樣選取長度為n的字符串進行比較,直到str的末尾(實際比較時,下標移動到n-m)。這樣的時間復雜度是O(n*m)。

KMP算法:可以實現復雜度為O(m+n)

為何簡化了時間復雜度:
充分利用了目標字符串ptr的性質(比如里面部分字符串的重復性,即使不存在重復字段,在比較時,實現最大的移動量)。
上面理不理解無所謂,我說的其實也沒有深刻剖析里面的內部原因。

考察目標字符串ptr
ababaca
這里我們要計算一個長度為m的轉移函數next。

next數組的含義就是一個固定字符串的最長前綴和最長后綴相同的長度。

比如:abcjkdabc,那么這個數組的最長前綴和最長后綴相同必然是abc。
cbcbc,最長前綴和最長后綴相同是cbc。
abcbc,最長前綴和最長后綴相同是不存在的。

**注意最長前綴:是說以第一個字符開始,但是不包含最后一個字符。
比如aaaa相同的最長前綴和最長后綴是aaa。**
對于目標字符串ptr,ababaca,長度是7,所以next[0],next[1],next[2],next[3],next[4],next[5],next[6]分別計算的是
a,ab,aba,abab,ababa,ababac,ababaca的相同的最長前綴和最長后綴的長度。由于a,ab,aba,abab,ababa,ababac,ababaca的相同的最長前綴和最長后綴是“”,“”,“a”,“ab”,“aba”,“”,“a”,所以next數組的值是[-1,-1,0,1,2,-1,0],這里-1表示不存在,0表示存在長度為1,2表示存在長度為3。這是為了和代碼相對應。

下圖中的1,2,3,4是一樣的。1-2之間的和3-4之間的也是一樣的,我們發現A和B不一樣;之前的算法是我把下面的字符串往前移動一個距離,重新從頭開始比較,那必然存在很多重復的比較。現在的做法是,我把下面的字符串往前移動,使3和2對其,直接比較C和A是否一樣。

這里寫圖片描述

這里寫圖片描述

代碼解析

void cal_next(char *str, int *next, int len){  next[0] = -1;//next[0]初始化為-1,-1表示不存在相同的最大前綴和最大后綴  int k = -1;//k初始化為-1  for (int q = 1; q <= len-1; q++)  {    while (k > -1 && str[k + 1] != str[q])//如果下一個不同,那么k就變成next[k],注意next[k]是小于k的,無論k取任何值。    {      k = next[k];//往前回溯    }    if (str[k + 1] == str[q])//如果相同,k++    {      k = k + 1;    }    next[q] = k;//這個是把算的k的值(就是相同的最大前綴和最大后綴長)賦給next[q]  }}

KMP

這個和next很像,具體就看代碼,其實上面已經大概說完了整個匹配過程。

int KMP(char *str, int slen, char *ptr, int plen){  int *next = new int[plen];  cal_next(ptr, next, plen);//計算next數組  int k = -1;  for (int i = 0; i < slen; i++)  {    while (k >-1&& ptr[k + 1] != str[i])//ptr和str不匹配,且k>-1(表示ptr和str有部分匹配)      k = next[k];//往前回溯    if (ptr[k + 1] == str[i])      k = k + 1;    if (k == plen-1)//說明k移動到ptr的最末端    {      //cout << "在位置" << i-plen+1<< endl;      //k = -1;//重新初始化,尋找下一個      //i = i - plen + 1;//i定位到該位置,外層for循環i++可以繼續找下一個(這里默認存在兩個匹配字符串可以部分重疊),感謝評論中同學指出錯誤。      return i-plen+1;//返回相應的位置    }  }  return -1; }

測試

  char *str = "bacbababadababacambabacaddababacasdsd";  char *ptr = "ababaca";  int a = KMP(str, 36, ptr, 7);  return 0;

注意如果str里有多個匹配ptr的字符串,要想求出所有的滿足要求的下標位置,在KMP算法需要稍微修改一下。見上面注釋掉的代碼。

復雜度分析

next函數計算復雜度是(m),開始以為是O(m^2),后來仔細想了想,cal__next里的while循環,以及外層for循環,利用均攤思想,其實是O(m),這個以后想好了再寫上。

………………………………………..分割線……………………………………..
其實本文已經結束,后面的只是針對評論里的疑問,我嘗試著進行解答的。

進一步說明(2018-3-14)

看了評論,大家對cal_next(..)函數和KMP()函數里的

while (k > -1 && str[k + 1] != str[q])    {      k = next[k];    }

while (k >-1&& ptr[k + 1] != str[i])      k = next[k];

這個while循環和k=next[k]很疑惑!
確實啊,我開始看這幾行代碼,相當懵逼,這寫的啥啊,為啥這樣寫;后來上機跑了一下,慢慢了解到為何這樣寫了。這幾行代碼,可謂是對KMP算法本質得了解非常清楚才能想到的。很牛逼!
直接看cal_next(..)函數:
首先我們看第一個while循環,它到底干了什么。

在此之前,我們先回到原程序。原程序里有一個大的for()循環,那這個for()循環是干嘛的?

這個for循環就是計算next[0],next[1],…next[q]…的值。

里面最后一句next[q]=k就是說明每次循環結束,我們已經計算了ptr的前(q+1)個字母組成的子串的“相同的最長前綴和最長后綴的長度”。(這句話前面已經解釋了?。?這個“長度”就是k。

好,到此為止,假設循環進行到 第 q 次,即已經計算了next[q],我們是怎么計算next[q+1]呢?

比如我們已經知道ababab,q=4時,next[4]=2(k=2,表示該字符串的前5個字母組成的子串ababa存在相同的最長前綴和最長后綴的長度是3,所以k=2,next[4]=2。這個結果可以理解成我們自己觀察算的,也可以理解成程序自己算的,這不是重點,重點是程序根據目前的結果怎么算next[5]的).,那么對于字符串ababab,我們計算next[5]的時候,此時q=5, k=2(上一步循環結束后的結果)。那么我們需要比較的是str[k+1]和str[q]是否相等,其實就是str[1]和str[5]是否相等!,為啥從k+1比較呢,因為上一次循環中,我們已經保證了str[k]和str[q](注意這個q是上次循環的q)是相等的(這句話自己想想,很容易理解),所以到本次循環,我們直接比較str[k+1]和str[q]是否相等(這個q是本次循環的q)。
如果相等,那么跳出while(),進入if(),k=k+1,接著next[q]=k。即對于ababab,我們會得出next[5]=3。 這是程序自己算的,和我們觀察的是一樣的。
如果不等,我們可以用”ababac“描述這種情況。 不等,進入while()里面,進行k=next[k],這句話是說,在str[k + 1] != str[q]的情況下,我們往前找一個k,使str[k + 1]==str[q],是往前一個一個找呢,還是有更快的找法呢? (一個一個找必然可以,即你把 k = next[k] 換成k- -也是完全能運行的(更正:這句話不對啊,把k=next[k]換成k亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

欧美在线www| 精品久久久久久久大神国产| 91精品国产高清自在线看超| 久久99久久99精品中文字幕| 欧美激情免费视频| 欧美国产高跟鞋裸体秀xxxhd| 欧美中文字幕在线视频| 成人性生交大片免费看视频直播| 欧美成人手机在线| 久久五月天综合| 久久久久久久成人| 亚洲成人久久网| 欧美体内谢she精2性欧美| 久久精品国产亚洲一区二区| 欧美高清视频在线播放| 欧美成人午夜激情| www.亚洲一二| 日本人成精品视频在线| 68精品国产免费久久久久久婷婷| 欧美成人在线免费视频| 欧美日韩ab片| 国产欧美va欧美va香蕉在线| 久色乳综合思思在线视频| 九九热在线精品视频| 日韩av在线最新| 成人信息集中地欧美| 日韩欧美大尺度| 日韩成人在线网站| 国产亚洲精品美女| 亚洲在线免费看| 亚洲性生活视频在线观看| 欧美国产高跟鞋裸体秀xxxhd| 久久久亚洲精品视频| 国产999在线观看| 超碰日本道色综合久久综合| 亚洲精品免费一区二区三区| 国产精品色悠悠| xxx欧美精品| 国产精品一区二区性色av| 91精品国产色综合| 97视频com| 国产精品18久久久久久麻辣| www国产精品视频| 亚洲国产精品字幕| 午夜精品福利视频| 超在线视频97| 91精品视频在线播放| 国产亚洲欧洲高清一区| 久久亚洲一区二区三区四区五区高| 国产丝袜一区二区| 狠狠躁夜夜躁久久躁别揉| 亚洲成年人在线| 亚洲аv电影天堂网| 亚洲自拍偷拍视频| 国产精品天天狠天天看| 久久久999国产精品| 97国产真实伦对白精彩视频8| 国产精品美腿一区在线看| 久久综合国产精品台湾中文娱乐网| 国产精品国产福利国产秒拍| 久久伊人色综合| 亚洲成人精品久久| 国产91在线播放精品91| 精品久久久久久亚洲精品| 2018日韩中文字幕| 欧美人交a欧美精品| 91精品国产综合久久香蕉| 亚洲成年人影院在线| 亚洲欧美日韩第一区| 日韩高清免费观看| 日本一欧美一欧美一亚洲视频| 91免费综合在线| 成人乱色短篇合集| 久久全球大尺度高清视频| 久久99青青精品免费观看| 麻豆国产va免费精品高清在线| 精品福利在线视频| 国产精品aaaa| 亚洲福利精品在线| 色偷偷88888欧美精品久久久| 久久中文字幕在线| 91色精品视频在线| 久久在线精品视频| 欧美极品在线视频| 亚洲综合色激情五月| 成人午夜两性视频| 日韩在线观看成人| 中文字幕精品一区久久久久| 亚洲天堂成人在线视频| 菠萝蜜影院一区二区免费| www.欧美精品| 亚洲精品大尺度| 777国产偷窥盗摄精品视频| 欧美高清视频一区二区| 国产美女精品视频| 92版电视剧仙鹤神针在线观看| 国产精品wwww| 国产亚洲精品久久久久久777| 国产偷亚洲偷欧美偷精品| 久久久精品视频在线观看| 北条麻妃在线一区二区| 亚洲国产成人精品女人久久久| 亚洲一区二区免费| 国产精品电影久久久久电影网| 91人成网站www| 亚洲人成在线观| 亚洲自拍小视频| 亚洲第一色在线| 中文字幕亚洲综合久久筱田步美| 亚洲美女av网站| 5566日本婷婷色中文字幕97| 538国产精品视频一区二区| 欧美成人黄色小视频| 欧美日韩国产色视频| 亚洲免费成人av电影| 欧美成人激情视频免费观看| 日韩电影免费观看在线| 在线视频日韩精品| 精品国产一区二区三区久久| 91精品久久久久久久| 日韩欧美在线网址| 热99精品里视频精品| 69**夜色精品国产69乱| 日韩中文综合网| 视频在线观看99| 亚洲欧洲激情在线| 91精品国产色综合| 亚洲香蕉成视频在线观看| 欧美丰满老妇厨房牲生活| 26uuu另类亚洲欧美日本老年| 日韩福利伦理影院免费| 欧美精品videofree1080p| 久久精品亚洲一区| 国产午夜精品视频免费不卡69堂| 日韩黄色在线免费观看| 亚洲成**性毛茸茸| 欧美丰满老妇厨房牲生活| 亚洲xxxx在线| 久久频这里精品99香蕉| 亚洲在线免费观看| 成人做爰www免费看视频网站| 亚洲黄页视频免费观看| 国产一区私人高清影院| 亚洲最大成人网色| 久久国产精品99国产精| 欧美视频中文在线看| 亚洲人成在线观看| 国产精品极品在线| 欧美性生活大片免费观看网址| 日韩国产欧美区| 亚洲色图色老头| 中文字幕日韩精品有码视频| 欧美性猛交xxxx偷拍洗澡| 亚洲精品成人久久久| 久久综合久久美利坚合众国| 成人免费看片视频| 3344国产精品免费看| 亚洲**2019国产| 91视频88av| 亚洲精品国产品国语在线| 日韩小视频在线观看| 久热99视频在线观看| 91网站在线免费观看| 亚洲精品国产精品国自产观看浪潮|