字符串匹配算法(KMP)

兩個(gè)字符串A、B,在A字符串中查找B字符串(分別長(zhǎng)為m,n)茵典,如果找到了懂扼,返回B字符串在A字符串中第一次出現(xiàn)的下標(biāo)牙言。

暴力的方法是在A[k]锋边,從k=0開始對(duì)比B字符串匯中的字符歌馍,如果失敗了黍氮,那么k++跛十,時(shí)間復(fù)雜度為mn彤路。
這種算法忽略的B字符串中特性,也就是說(shuō)芥映,只向后移動(dòng)一位對(duì)就開始對(duì)比洲尊,實(shí)際中,可能需要移動(dòng)的位數(shù)更多屏轰。

所以颊郎,需要先找一下規(guī)律,當(dāng)在A[k]出對(duì)比B字符串失敗后霎苗,應(yīng)該向后移動(dòng)多少位(也就是A[k+?])姆吭,開始對(duì)比?

引入一個(gè)概念:字符串前后綴最大相同長(zhǎng)度
也就是一個(gè)字符串唁盏,如果前面n位和后面n位字符完全相同(順序一樣内狸,不是鏡像)。那么n就是字符串前后綴最大相同長(zhǎng)度(名字不要在意厘擂,別的都是公共部分昆淡,我覺(jué)得別扭)。假設(shè)該字符串長(zhǎng)為m,那么n的取值范圍為0~m刽严,也就是說(shuō)這個(gè)前綴和后綴可以重疊昂灵,可以完全重疊。

假若舞萄,在A[k]中匹配B眨补,在B[h]開始不同,那么直接向后移動(dòng)B字符串前h位的前后綴最大長(zhǎng)度(以后都稱為next[h])既可倒脓。
當(dāng)在B[h]匹配失敗后撑螺,B[h-next[k]]B[h]的字符串(前綴)與B[0]B[next[k]]的字符串(后綴)是相同的,在A中對(duì)應(yīng)的位置也是相同的崎弃。此時(shí)甘晤,只需要將B[0]移動(dòng)到B[h-next[h]]位置,移動(dòng)后饲做,B在A中的前next[h]位是已經(jīng)匹配好的线婚。所以不需要再?gòu)?code>B[0]開始匹配了。

為什么可以跳過(guò)這么多的位置盆均,重要的要理解next[]的構(gòu)造過(guò)程酌伊。

構(gòu)造過(guò)程之這樣子的:
next從下標(biāo)1開始存儲(chǔ),因?yàn)锽從開始到結(jié)束缀踪,子字符串長(zhǎng)度為0沒(méi)意義居砖。當(dāng)子字符串長(zhǎng)度為1是,next[1]=1驴娃。

假設(shè)當(dāng)子字符串長(zhǎng)度為k時(shí)(也就是B[k-1]以及之前)奏候,前后綴最大相同長(zhǎng)度為m

子字符串長(zhǎng)度為k+1:當(dāng)B[k]=B[m+1]時(shí) 唇敞,(B[k]為之前的后綴之后的第一個(gè)字符蔗草,B[m+1]是前綴之后的第一個(gè)字符,如果相等疆柔,就是前后綴最大相同長(zhǎng)度+1)咒精,所以next[k+1]=next[k-1]+1

不想等時(shí):開始比較B[m]位和B[k]位旷档,如果相等也就是模叙,之前的后綴和前綴,在后面有公共部分鞋屈。其相同長(zhǎng)度可能為next[m]+1范咨,因?yàn)?code>B[m-1]子字符串的前綴的后一位可能不等于B[m]。如果相等厂庇,那么next[k]=next[next[k]]+1
否則渠啊,再比較B[m-1]B[k],同上权旷。

#include <vector>
#include <iostream>
#include <string>

using namespace std;


vector<int> calNext(const string &str)
{
    int len = str.size();                                   //總長(zhǎng)度
    vector<int> next(len + 1);
    next[2] = 0;
    int sublen;                                             //要計(jì)算next的子字符串
    for(int i = 2; i < len ; i++)  
    {
        sublen = i+1;
        if(str[i] == str[next[sublen-1]] )                  //sublen - 1 上一個(gè)子字符串長(zhǎng)度
        {                                                   //next[sublen - 1] 上個(gè)子字符串前綴的后一位
            next[sublen] = next[sublen-1] +1;
        }else{
        
        //B子字符串前綴右移替蛉,以此比較其前綴與str[i]
        for(int j = next[sublen-1] -1  ; j >= 0; j--)         
        {
            //比較子字符串前綴與str[i]
            if(str[next[j]] == str[i])
            {
                //如果子字符串前綴后一位與str[i]相同
                //那么比較以前綴為子字符串的前綴的后一位與str[i]
                //這樣就還是比較了一個(gè)子字符串的前綴和后綴與待計(jì)算next的字符
                if(str[next[next[j]-1]] == str[i])
                //上面的-1,是將長(zhǎng)度轉(zhuǎn)化為下標(biāo),next中的都是下標(biāo)
                {
                    next[i+1] = next[next[j]]+1;
                    break;
                }
            }
        }
        }
    }
return next;
}

int main()
{
    string str("ABCKACBACLABKJ");
    str="abaabcaba";
    vector<int> next = calNext(str);

    for(int i = 1 ;i < next.size();i++)
    {
        cout<<next[i]<<" ";
    }
    cout<<endl;
}

這就是next的構(gòu)建拄氯,其基本思想是:
比較一個(gè)子字符串的前綴后一位和后綴后一位與待計(jì)算next字符躲查,如果一樣,那么待計(jì)算字符的next值就是子字符串的next值+1.
現(xiàn)在next中存儲(chǔ)的就是每次跳轉(zhuǎn)的時(shí)候額外跳轉(zhuǎn)的歩數(shù)坤邪,同時(shí)也是跳轉(zhuǎn)以后搜索的起點(diǎn)熙含。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市艇纺,隨后出現(xiàn)的幾起案子怎静,更是在濱河造成了極大的恐慌,老刑警劉巖黔衡,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚓聘,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡盟劫,警方通過(guò)查閱死者的電腦和手機(jī)夜牡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人塘装,你說(shuō)我怎么就攤上這事急迂。” “怎么了蹦肴?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵僚碎,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我阴幌,道長(zhǎng)勺阐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任矛双,我火速辦了婚禮渊抽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘议忽。我一直安慰自己懒闷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布徙瓶。 她就那樣靜靜地躺著毛雇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪侦镇。 梳的紋絲不亂的頭發(fā)上灵疮,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音壳繁,去河邊找鬼震捣。 笑死,一個(gè)胖子當(dāng)著我的面吹牛闹炉,可吹牛的內(nèi)容都是我干的蒿赢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼渣触,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼羡棵!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起嗅钻,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤皂冰,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后养篓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秃流,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年柳弄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了舶胀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嚣伐,靈堂內(nèi)的尸體忽然破棺而出糖赔,到底是詐尸還是另有隱情,我是刑警寧澤纤控,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布挂捻,位于F島的核電站,受9級(jí)特大地震影響船万,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜骨田,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一耿导、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧态贤,春花似錦舱呻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至柿冲,卻和暖如春茬高,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背假抄。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工怎栽, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宿饱。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓熏瞄,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親谬以。 傳聞我的和親對(duì)象是個(gè)殘疾皇子强饮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容