KMP算法

KMP所解決的問題:判斷一個串是否是另一個串的子串。
例如:

給兩個字符串S1和S2匀伏,問S2是否是S1的子串洒忧?
數(shù)據(jù)范圍:0<|S2|<=|S1|<=100000

Input
第一行輸入一個字符串S1,第二行輸入一個字符串S2够颠,保證0<|S2|<=|S1|<=100000

Output
如果S2是S1的子串熙侍,輸出“YES”.
否則,輸出“NO”.

樣例
Sample Input
AAABAAABAAABAAAD
AAABAAAD

ABAAB
ABB

Sample Output
YES
NO

注:一個字符串的子串指的是字符串某一段連續(xù)的部分(比如第一個例子),可以是其本身核行。
而不連續(xù)的部分牢硅,一般稱作為子序列!(比如第二個例子芝雪,ABB是ABAAB的子序列而不是子串)

通常做法:
暴力求解

暴力求解.png

暴力求解雖然可以計(jì)算出來,但是其時間復(fù)雜度往往是不允許的
時間復(fù)雜度:O(|S1||S2|)
當(dāng)|S1|=|S2|=100000時综苔,|S1|
|S2|=10000000000 也就是十個0惩系,100億!如筛!
用超級計(jì)算機(jī)還是有希望1s跑完的(●ˇ?ˇ●)

暴力匹配不能快速解決堡牡,有更好的辦法嗎?
有杨刨!KMP算法晤柄!

①前綴后綴最大值:
一個長度為N的字符串S,它有N+1個前綴(包括空前綴)和N+1個后綴(包括空后綴)
比如ABC妖胀,有4個前綴芥颈,空,A赚抡,AB爬坑,ABC
有4個后綴,空涂臣,C盾计,BC,ABC
比如AAA赁遗,有4個前綴署辉,空,A岩四,AA哭尝,AAA
有4個后綴,空炫乓,A刚夺,AA,AAA


前綴與后綴

如果不算自身(ABABABA)末捣,很容易發(fā)現(xiàn)字符串S前綴后綴最大值為5侠姑,即ABABA。

②next[ ]數(shù)組
知道了最大前綴后綴的定義箩做,現(xiàn)在就要想辦法把每個字符所在位置的最大前綴后綴記錄下來莽红,這里用的是next[ ]。

NEXT數(shù)組.png

next的數(shù)組構(gòu)建

int init[1000005];//原始字符串
int pp[1000005];//匹配字符串
int Next[1000005];//next數(shù)組
int m,n;//m=strlen(init);n=strlen(pp);
void creat_next(void)
{
    int j=0;
    next1[0]=0;
    for(int i=1; i<n; i++)
    {
        if(pp[i]==pp[j])
        {
            Next[i]=Next[i-1]+1;
            j++;
        }
        else
        {
            while(1)
            {
                if(j!=0)j=Next[j-1];
                else break;
                if(pp[i]==pp[j])
                {
                    Next[i]=j+1;
                    j++;
                    break;
                }
            }
        }
    }
}
NEXT.png

對比下

NEXT.png

Number Sequence

int ys[1000005];//原始字符串
int pp[1000005];//匹配字符串
int next1[1000005];//next數(shù)組
int m,n;//m=strlen(ys);n=strlen(pp);
void findnext(void)
{
    int j=0;
    next1[0]=0;
    for(int i=1; i<n; i++)
    {
        if(pp[i]==pp[j])
        {
            next1[i]=next1[i-1]+1;
            j++;
        }
        else
        {
            while(1)
            {
                if(j!=0)j=next1[j-1];
                else break;
                if(pp[i]==pp[j])
                {
                    next1[i]=j+1;
                    j++;
                    break;
                }
            }
        }
    }
}

int kmp(void)
{
    int i=0,j=0;
    findnext();
    while(i<m)
    {
        if(ys[i]==pp[j])
        {
            i++;j++;
            if(j==n)return i-n+1;
        }
        else if(j>0)j=next1[j-1];
        else if(j==0)i++;
    }
    return -1;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&m,&n);
        for(int i=0;i<m;i++)
            scanf("%d",&ys[i]);
        for(int i=0;i<n;i++)
            scanf("%d",&pp[i]);
        int ans=kmp();
        printf("%d\n",ans);
    }
    return 0;
}

Oulipo

int m,n;
int nex[1000005];

void findnext(char *pp)
{
    memset(nex,0,sizeof(nex));
    int j=0;
    nex[0]=0;
    for(int i=1; i<n; i++)
        if(pp[i]==pp[j])
        {
            nex[i]=nex[i-1]+1;
            j++;
        }
        else
            while(1)
            {
                if(j!=0)j=nex[j-1];
                else break;
                if(pp[i]==pp[j])
                {
                    nex[i]=j+1;
                    j++;
                    break;
                }
            }
}

int kmp(char *ys,char *pp)
{
    int i=0,j=0,ans=0;
    while(i<m)
    {
        if(ys[i]==pp[j])
        {
            i++;
            j++;
            if(j==n)ans++;
        }
        else if(j>0)j=nex[j-1];
        else if(j==0)i++;
    }
    return ans;
}

int main()
{
    char pp[10005];
    char ys[1000005];
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",pp);
        n=strlen(pp);
        findnext(pp);
        scanf("%s",ys);
        m=strlen(ys);
        printf("%d\n",kmp(ys,pp));
    }
    return 0;
}

以上模版轉(zhuǎn)自fold2(http://www.reibang.com/p/fdd43ae2892f?utm_campaign=maleskine&utm_content=note&utm_medium=reader_share&utm_source=weibo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市安吁,隨后出現(xiàn)的幾起案子醉蚁,更是在濱河造成了極大的恐慌,老刑警劉巖鬼店,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件网棍,死亡現(xiàn)場離奇詭異,居然都是意外死亡妇智,警方通過查閱死者的電腦和手機(jī)滥玷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來巍棱,“玉大人惑畴,你說我怎么就攤上這事『结悖” “怎么了如贷?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長到踏。 經(jīng)常有香客問我杠袱,道長,這世上最難降的妖魔是什么夭禽? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任霞掺,我火速辦了婚禮,結(jié)果婚禮上讹躯,老公的妹妹穿的比我還像新娘菩彬。我一直安慰自己,他們只是感情好潮梯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布骗灶。 她就那樣靜靜地躺著,像睡著了一般秉馏。 火紅的嫁衣襯著肌膚如雪耙旦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天免都,我揣著相機(jī)與錄音,去河邊找鬼帆竹。 笑死绕娘,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的险领。 我是一名探鬼主播绢陌,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼臭笆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起衅谷,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蚀苛,失蹤者是張志新(化名)和其女友劉穎玷氏,沒想到半個月后渗蟹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體雌芽,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡屉佳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了髓堪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡玉雾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出复旬,到底是詐尸還是另有隱情冲泥,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布钧舌,位于F島的核電站又官,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜审编,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一件炉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧缅阳,春花似錦、人聲如沸呵燕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽澄干。三九已至,卻和暖如春从媚,著一層夾襖步出監(jiān)牢的瞬間到千,已是汗流浹背憔四。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胯究,地道東北人剥哑。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓座哩,卻偏偏與公主長得像根穷,于是被迫代替她去往敵國和親缠诅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

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

  • 數(shù)據(jù)結(jié)構(gòu)與算法--KMP算法查找子字符串 部分內(nèi)容和圖片來自這三篇文章: 這篇文章乍迄、這篇文章管引、還有這篇他們寫得非常...
    sunhaiyu閱讀 1,737評論 1 21
  • 數(shù)據(jù)結(jié)構(gòu) 第8講 KMP算法 講這個算法之前,我們首先了解幾個概念: 串:又稱字符串闯两,是由零個或多個字符組成的有限...
    rainchxy閱讀 1,300評論 0 3
  • 文章大綱:1.KMP算法概念2.KMP算法中最核心的next[] 數(shù)組是如何生成的3.使用KMP算法 匹配字符串 ...
    檸檬烏冬面閱讀 815評論 0 3
  • KMP的由來 在KMP算法之前,對文本進(jìn)行匹配時使用的是樸素模式匹配算法,也就是最簡單匹配算法.當(dāng)然運(yùn)行效率也是讓...
    圣光懺悔閱讀 1,756評論 2 13
  • 原鏈接:KMP算法詳解|CloudWong 傳統(tǒng)的字符串匹配模式(暴力循環(huán)) 子串的定位操作通常稱作串的串的匹配模...
    簡Cloud閱讀 3,911評論 1 22