演算法導論————KMP

來源:互聯網
上載者:User

標籤:訪問   檔案   http   利用   ring   轉移   abc   首碼   怎麼辦   

例題傳送門:caioj1177

KMP模版:子串是否出現

【題意】
有兩個字串SA和SB,SA是母串,SB是子串,問子串SB是否在母串SA中出現過。
如果出現過輸出第一次出現的起始位置和結束位置,否則輸出"NO"
【輸入檔案】
第一行SA(1<= 長度<=1000000)
第二行SB(1<= 長度<=1000)
【輸出檔案】
如果SB在SA中出現過輸出第一次出現的起始位置和結束位置,否則輸出"NO"
【範例1輸入】
aaaaabaa
aab
【範例1輸出】
4 6
【範例2輸入】
aaaaabaa
aax
【範例2輸出】
NO

演算法分析:

  KMP其實就是一種偷懶的方式,通過訪問前面已經遍曆過的位置來首先給定一個可繼承的值,然後暴力(汗......)

  首先定義一個p數組,p[i]=j時,代表SA字串[1...j]與SA字串[i-j+1...i]所形成的子串完全相同

  那麼我們怎麼得出這個p數組呢?

  就是暴力+偷懶!!!(其實前面已經講了,尷尬)

  當我們訪問到i這個點時,我們先訪問一下i-1,因為我們訪問到i的時候已經把1~i-1的p數組求出來了,那麼請看下面的圖:

  我們設j=p[i-1],i-1-j+1=i-j,那麼我們可以知道SA[1...j]=SA[i-j...i-1],也就是的紅色區間,那假如SA[j+1]=SA[i]的話,我們就可以直接p[i]=j+1對吧

  但是現實是殘酷的(AC沒有那麼容易~),那麼當SA[j+1]!=SA[i]的時候怎麼辦呢?那麼我們就找p[j]!!!

  我們再設一個變數k=p[j],因為p[j]的定義,所以我們可以得到SA[1...k]=SA[j-k+1...j],也就是前兩個棕色區間,這時因為兩個紅色區間相同,所以我們可以得到SA[1...k]=SA[i-j...i-j+k-1],也就是第一個和第三個棕色區

間相等,接著又可以得到SA[j-k+1...j]=SA[i-k(i-1-k+1)...i-1],也就是第二個和第四個的棕色區間相等,然後!!!我們得到四個棕色區間相等!!!我們就可以判斷SA[k+1]和SA[i]是否相等來求p[i],如果相等,p[i]=k+1,

否則繼續找p[k]。一直找啊找,直到找到沒得找也就是當前的p[p[p[p[p[p[.......的值為0時,那麼我們就判斷SA[1]和SA[i]是否相同,相同p[i]=1,否則p[i]=0

  其實也不算暴力,而是利用p數組的定義來尋找前面可以用來繼承的點!!

  但是到了這裡,還沒有完成KMP的學習

  我們的p數組只對SA字串,也就是題目中的子串進行了處理

  那麼p數組對於我們求答案有什麼協助呢?

  

  我們設j為SB字串中的i-1位置開始所組成的尾碼,與SA字串中的1位置開始的首碼的最長公用長度,也就是SA[1...j]=SB[i-j(i-1-j+1)...j-1],那麼我們可以判斷SA[j+1]和SB[i]是否相等,相等就記錄j的值,不相等就找p[j]!!!是不是似曾相識的步驟,沒錯!就是把SB中的i轉移到SA中進行求解,這樣就是KMP的全部了!

參考代碼:
#include<cstdio>#include<cstring>using namespace std;char sa[1110000],sb[1100];//sa是母串,sb是子串int p[1100];//p數組是為子串準備的,p的含義和母串一點關係都沒有。//p[i]表示sb中 以第i個字元為結尾,往前最多拉多少個字元(sb[i]結尾的尾碼)可以完全符合sb的首碼//比如  sb="abcdabc"中 p[7]=3, 就這樣,我當你理解p[i]的含義了int main(){    int lena,lenb,i,j;    scanf("%s",sa+1);lena=strlen(sa+1);    scanf("%s",sb+1);lenb=strlen(sb+1);    //製造P數組    p[1]=0;    for(i=2;i<=lenb;i++)    {        j=p[i-1];//先記錄p[i-1]        while(j>0&&sb[i]!=sb[j+1]) j=p[j];        /*        這裡有兩種情況        如果j+1的位置的字元等於i位置的字元的話,那就直接把p[i]=j+1        否則就找j的p值,因為1~sb[p[j]]一定是1~sb[j]的尾碼        */        if(sb[i]==sb[j+1]) p[i]=j+1;else p[i]=0;    }    int st,ed;    j=0;    for(i=1;i<=lena;i++)//緊接著用p數組來匹配母串    {        while(j>0&&sa[i]!=sb[j+1]) j=p[j];        if(sa[i]==sb[j+1]) j++;        if(j==lenb){ed=i;st=i-lenb+1;break;}//得到答案後就記錄開頭與結尾    }    if(j==lenb) printf("%d %d\n",st,ed);    else printf("NO\n");    return 0;}

 

演算法導論————KMP

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.