• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 5  文章 - 2  trackbacks - 0
            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            There can be no Triumph without Loss,No Victory without Suffering,No Freedom without Sacrifice. All you have to decide is what to do with the time that is given to you. Get busy Living, or Get busy Dying?

            常用鏈接

            留言簿

            隨筆分類(4)

            隨筆檔案(5)

            文章分類(88)

            文章檔案(10)

            Andriod

            Language

            OpenCV&OpenSSLink

            OpenSource

            Others

            Python&Ruby

            WP7

            WTL

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            ???
            ?? 如果機房馬上要關門了,或者你急著要和MM約會,請直接跳到第六個自然段。
            我們這里說的KMP不是拿來放 電影的(雖然我很喜歡這個軟件),而是一種算法。KMP算法是拿來處理字符串匹配的。換句話說,給你兩個字符串,你需要回答,B串是否是A串的子串(A串 是否包含B串)。比如,字符串A="I'm matrix67",字符串B="matrix",我們就說B是A的子串。你可以委婉地問你的MM:“假如你要向你喜歡的人表白的話,我的名字是你的告白 語中的子串嗎?”
            ????解決這類問題,通常我們的方法是枚舉從A串的什么位置起開始與B匹配,然后驗證是否匹配。假如A串長度為n,B串長度為 m,那么這種方法的復雜度是O (mn)的。雖然很多時候復雜度達不到mn(驗證時只看頭一兩個字母就發現不匹配了),但我們有許多“最壞情況”,比如,A= "aaaaaaaaaaaaaaaaaaaaaaaaaab",B="aaaaaaaab"。我們將介紹的是一種最壞情況下O(n)的算法(這里假設 m<=n),即傳說中的KMP算法。
            ????之所以叫做KMP,是因為這個算法是由Knuth、Morris、Pratt三個提出來的,取 了這三個人的名字的頭一個字母。這時,或許你突然明白了AVL 樹為什么叫AVL,或者Bellman-Ford為什么中間是一杠不是一個點。有時一個東西有七八個人研究過,那怎么命名呢?通常這個東西干脆就不用人名 字命名了,免得發生爭議,比如“3x+1問題”。扯遠了。
            ????個人認為KMP是最沒有必要講的東西,因為這個東西網上能找到很多資料。但網上 的講法基本上都涉及到“移動(shift)”、“Next函數”等概念,這非常容易產生誤解(至少一年半前我看這些資料學習KMP時就沒搞清楚)。在這 里,我換一種方法來解釋KMP算法。

            ????假如,A="abababaababacb",B="ababacb",我們來看看KMP 是怎么工作的。我們用兩個指針i和j分別表示,A[i-j+ 1..i]與B[1..j]完全相等。也就是說,i是不斷增加的,隨著i的增加j相應地變化,且j滿足以A[i]結尾的長度為j的字符串正好匹配B串的前 j個字符(j當然越大越好),現在需要檢驗A[i+1]和B[j+1]的關系。當A[i+1]=B[j+1]時,i和j各加一;什么時候j=m了,我們就 說B是A的子串(B串已經整完了),并且可以根據這時的i值算出匹配的位置。當A[i+1]<>B[j+1],KMP的策略是調整j的位置 (減小j值)使得A[i-j+1..i]與B[1..j]保持匹配且新的B[j+1]恰好與A[i+1]匹配(從而使得i和j能繼續增加)。我們看一看當 i=j=5時的情況。

            ????i = 1 2 3 4 5 6 7 8 9 ……
            ????A = a b a b a b a a b a b …
            ????B = a b a b a c b
            ????j = 1 2 3 4 5 6 7


            ????此 時,A[6]<>B[6]。這表明,此時j不能等于5了,我們要把j改成比它小的值j'。j'可能是多少呢?仔細想一下,我們發現,j'必須 要使得B[1..j]中的頭j'個字母和末j'個字母完全相等(這樣j變成了j'后才能繼續保持i和j的性質)。這個j'當然要越大越好。在這里,B [1..5]="ababa",頭3個字母和末3個字母都是"aba"。而當新的j為3時,A[6]恰好和B[4]相等。于是,i變成了6,而j則變成了 4:

            ????i = 1 2 3 4 5 6 7 8 9 ……
            ????A = a b a b a b a a b a b …
            ????B =???? a b a b a c b
            ????j =???? 1 2 3 4 5 6 7


            ????從 上面的這個例子,我們可以看到,新的j可以取多少與i無關,只與B串有關。我們完全可以預處理出這樣一個數組P[j],表示當匹配到B數組的第j個字母而 第j+1個字母不能匹配了時,新的j最大是多少。P[j]應該是所有滿足B[1..P[j]]=B[j-P[j]+1..j]的最大值。
            ????再后來,A[7]=B[5],i和j又各增加1。這時,又出現了A[i+1]<>B[j+1]的情況:

            ????i = 1 2 3 4 5 6 7 8 9 ……
            ????A = a b a b a b a a b a b …
            ????B =???? a b a b a c b
            ????j =???? 1 2 3 4 5 6 7


            ????由于P[5]=3,因此新的j=3:

            ????i = 1 2 3 4 5 6 7 8 9 ……
            ????A = a b a b a b a a b a b …
            ????B =???????? a b a b a c b
            ????j =???????? 1 2 3 4 5 6 7


            ????這時,新的j=3仍然不能滿足A[i+1]=B[j+1],此時我們再次減小j值,將j再次更新為P[3]:

            ????i = 1 2 3 4 5 6 7 8 9 ……
            ????A = a b a b a b a a b a b …
            ????B =???????????? a b a b a c b
            ????j =???????????? 1 2 3 4 5 6 7


            ????現在,i還是7,j已經變成1了。而此時A[8]居然仍然不等于B[j+1]。這樣,j必須減小到P[1],即0:

            ????i = 1 2 3 4 5 6 7 8 9 ……
            ????A = a b a b a b a a b a b …
            ????B =?????????????? a b a b a c b
            ????j =???????????? 0 1 2 3 4 5 6 7


            ????終于,A[8]=B[1],i變為8,j為1。事實上,有可能j到了0仍然不能滿足A[i+1]=B[j+1](比如A[8]="d"時)。因此,準確的說法是,當j=0了時,我們增加i值但忽略j直到出現A[i]=B[1]為止。
            ????這個過程的代碼很短(真的很短),我們在這里給出:

            j:=0;
            for i:=1 to n do
            begin
            ?? while (j>0) and (B[j+1]<>A[i]) do j:=P[j];
            ?? if B[j+1]=A[i] then j:=j+1;
            ?? if j=m then
            ?? begin
            ??????writeln('Pattern occurs with shift ',i-m);
            ??????j:=P[j];
            ?? end;
            end;


            ????最后的j:=P[j]是為了讓程序繼續做下去,因為我們有可能找到多處匹配。
            ????這個程序或許比想像中的要簡單,因為對于i值的不斷增加,代碼用的是for循環。因此,這個代碼可以這樣形象地理解:掃描字符串A,并更新可以匹配到B的什么位置。

            ????現在,我們還遺留了兩個重要的問題:一,為什么這個程序是線性的;二,如何快速預處理P數組。
            ????為 什么這個程序是O(n)的?其實,主要的爭議在于,while循環使得執行次數出現了不確定因素。我們將用到時間復雜度的攤還分析中的主要策略,簡單地說 就是通過觀察某一個變量或函數值的變化來對零散的、雜亂的、不規則的執行次數進行累計。KMP的時間復雜度分析可謂攤還分析的典型。我們從上述程序的j 值入手。每一次執行while循環都會使j減小(但不能減成負的),而另外的改變j值的地方只有第五行。每次執行了這一行,j都只能加1;因此,整個過程 中j最多加了n個1。于是,j最多只有n次減小的機會(j值減小的次數當然不能超過n,因為j永遠是非負整數)。這告訴我們,while循環總共最多執行 了n次。按照攤還分析的說法,平攤到每次for循環中后,一次for循環的復雜度為O(1)。整個過程顯然是O(n)的。這樣的分析對于后面P數組預處理 的過程同樣有效,同樣可以得到預處理過程的復雜度為O(m)。
            ????預處理不需要按照P的定義寫成O(m^2)甚至O(m^3)的。我們可以通 過P[1],P[2],...,P[j-1]的值來獲得P[j]的值。對于剛才的B="ababacb",假如我們已經求出了 P[1],P[2],P[3]和P[4],看看我們應該怎么求出P[5]和P[6]。P[4]=2,那么P [5]顯然等于P[4]+1,因為由P[4]可以知道,B[1,2]已經和B[3,4]相等了,現在又有B[3]=B[5],所以P[5]可以由P[4] 后面加一個字符得到。P[6]也等于P[5]+1嗎?顯然不是,因為B[ P[5]+1 ]<>B[6]。那么,我們要考慮“退一步”了。我們考慮P[6]是否有可能由P[5]的情況所包含的子串得到,即是否P[6]=P[ P[5] ]+1。這里想不通的話可以仔細看一下:

            ????????1 2 3 4 5 6 7
            ????B = a b a b a c b
            ????P = 0 0 1 2 3 ?


            ????P[5]=3 是因為B[1..3]和B[3..5]都是"aba";而P[3]=1則告訴我們,B[1]、B[3]和B[5]都是"a"。既然P[6]不能由P[5] 得到,或許可以由P[3]得到(如果B[2]恰好和B[6]相等的話,P[6]就等于P[3]+1了)。顯然,P[6]也不能通過P[3]得到,因為 B[2]<>B[6]。事實上,這樣一直推到P[1]也不行,最后,我們得到,P[6]=0。
            ????怎么這個預處理過程跟前面的KMP主程序這么像呢?其實,KMP的預處理本身就是一個B串“自我匹配”的過程。它的代碼和上面的代碼神似:

            P[1]:=0;
            j:=0;
            for i:=2 to m do
            begin
            ?? while (j>0) and (B[j+1]<>B[i]) do j:=P[j];
            ?? if B[j+1]=B[i] then j:=j+1;
            ?? P[i]:=j;
            end;


            ????最后補充一點:由于KMP算法只預處理B串,因此這種算法很適合這樣的問題:給定一個B串和一群不同的A串,問B是哪些A串的子串。

            ????串匹配是一個很有研究價值的問題。事實上,我們還有后綴樹,自動機等很多方法,這些算法都巧妙地運用了預處理,從而可以在線性的時間里解決字符串的匹配。我們以后來說。

            ????昨天發現一個特別暈的事,知道怎么去掉BitComet的廣告嗎?把界面語言設成英文就行了。
            ????還有,金山詞霸和Dr.eye都可以去自殺了,Babylon素王道。
            posted on 2010-11-19 19:31 jemmyLiu 閱讀(242) 評論(0)  編輯 收藏 引用 所屬分類: C++BASE
            亚洲国产精久久久久久久| 色欲久久久天天天综合网精品| 狠狠狠色丁香婷婷综合久久俺| 久久青草国产精品一区| 欧美无乱码久久久免费午夜一区二区三区中文字幕 | 丁香狠狠色婷婷久久综合| 色综合久久天天综合| 亚州日韩精品专区久久久| 久久国产高清字幕中文| 久久亚洲日韩看片无码| 国内精品久久久久久久影视麻豆 | 国产精品午夜久久| 久久这里只有精品18| 亚洲欧美久久久久9999| 久久香蕉国产线看观看乱码| 亚洲国产视频久久| 国内精品免费久久影院| 99久久婷婷免费国产综合精品| 久久只有这里有精品4| 久久精品国产一区二区三区| 国内精品久久久久久99| 亚洲AV日韩精品久久久久久| 中文精品99久久国产 | 婷婷久久久亚洲欧洲日产国码AV | 久久久久无码精品国产| 亚洲一级Av无码毛片久久精品| 91精品国产综合久久四虎久久无码一级| 日韩人妻无码精品久久久不卡| 思思久久99热只有频精品66| 久久综合给合综合久久| 久久国产高清一区二区三区| 久久精品视频网| 色综合久久中文色婷婷| 国产精品九九久久免费视频 | 久久久久久午夜成人影院| 99久久夜色精品国产网站| 久久人妻少妇嫩草AV蜜桃| 久久久久久久女国产乱让韩| 伊人久久亚洲综合影院| 久久91精品国产91久| 亚洲愉拍99热成人精品热久久|