• <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
            <2011年2月>
            303112345
            6789101112
            13141516171819
            20212223242526
            272812345
            6789101112

            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

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

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

            ????假如,A="abababaababacb",B="ababacb",我們來看看KMP 是怎么工作的。我們用兩個指針i和j分別表示,A[i-j+ 1..i]與B[1..j]完全相等。也就是說,i是不斷增加的,隨著i的增加j相應(yīng)地變化,且j滿足以A[i]結(jié)尾的長度為j的字符串正好匹配B串的前 j個字符(j當(dāng)然越大越好),現(xiàn)在需要檢驗A[i+1]和B[j+1]的關(guān)系。當(dāng)A[i+1]=B[j+1]時,i和j各加一;什么時候j=m了,我們就 說B是A的子串(B串已經(jīng)整完了),并且可以根據(jù)這時的i值算出匹配的位置。當(dāng)A[i+1]<>B[j+1],KMP的策略是調(diào)整j的位置 (減小j值)使得A[i-j+1..i]與B[1..j]保持匹配且新的B[j+1]恰好與A[i+1]匹配(從而使得i和j能繼續(xù)增加)。我們看一看當(dāng) 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'可能是多少呢?仔細(xì)想一下,我們發(fā)現(xiàn),j'必須 要使得B[1..j]中的頭j'個字母和末j'個字母完全相等(這樣j變成了j'后才能繼續(xù)保持i和j的性質(zhì))。這個j'當(dāng)然要越大越好。在這里,B [1..5]="ababa",頭3個字母和末3個字母都是"aba"。而當(dāng)新的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無關(guān),只與B串有關(guān)。我們完全可以預(yù)處理出這樣一個數(shù)組P[j],表示當(dāng)匹配到B數(shù)組的第j個字母而 第j+1個字母不能匹配了時,新的j最大是多少。P[j]應(yīng)該是所有滿足B[1..P[j]]=B[j-P[j]+1..j]的最大值。
            ????再后來,A[7]=B[5],i和j又各增加1。這時,又出現(xiàn)了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


            ????現(xiàn)在,i還是7,j已經(jīng)變成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變?yōu)?,j為1。事實(shí)上,有可能j到了0仍然不能滿足A[i+1]=B[j+1](比如A[8]="d"時)。因此,準(zhǔn)確的說法是,當(dāng)j=0了時,我們增加i值但忽略j直到出現(xiàn)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]是為了讓程序繼續(xù)做下去,因為我們有可能找到多處匹配。
            ????這個程序或許比想像中的要簡單,因為對于i值的不斷增加,代碼用的是for循環(huán)。因此,這個代碼可以這樣形象地理解:掃描字符串A,并更新可以匹配到B的什么位置。

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

            ????????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]。事實(shí)上,這樣一直推到P[1]也不行,最后,我們得到,P[6]=0。
            ????怎么這個預(yù)處理過程跟前面的KMP主程序這么像呢?其實(shí),KMP的預(yù)處理本身就是一個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;


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

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

            ????昨天發(fā)現(xiàn)一個特別暈的事,知道怎么去掉BitComet的廣告嗎?把界面語言設(shè)成英文就行了。
            ????還有,金山詞霸和Dr.eye都可以去自殺了,Babylon素王道。
            posted on 2010-11-19 19:31 jemmyLiu 閱讀(244) 評論(0)  編輯 收藏 引用 所屬分類: C++BASE
            99久久99这里只有免费的精品| 亚洲精品乱码久久久久久 | 97久久国产亚洲精品超碰热| 久久亚洲AV成人出白浆无码国产| 97久久超碰国产精品旧版| 久久本道久久综合伊人| 中文字幕无码精品亚洲资源网久久| 久久66热人妻偷产精品9| 夜夜亚洲天天久久| 伊人久久无码中文字幕| 狠狠久久综合| 久久夜色精品国产欧美乱| 欧美久久综合九色综合| 久久人人爽爽爽人久久久| 欧美激情精品久久久久久| 久久精品亚洲中文字幕无码麻豆 | 久久天堂AV综合合色蜜桃网| 18岁日韩内射颜射午夜久久成人 | 一本大道加勒比久久综合| 亚洲狠狠婷婷综合久久蜜芽| 国产精品狼人久久久久影院| 久久夜色精品国产欧美乱| 人人妻久久人人澡人人爽人人精品| 高清免费久久午夜精品| 无码久久精品国产亚洲Av影片| 欧美一级久久久久久久大| 精品久久久久久综合日本| 久久精品国产99久久无毒不卡| 日日狠狠久久偷偷色综合96蜜桃 | 久久久久久久尹人综合网亚洲| 国产精品美女久久福利网站| 久久久久一本毛久久久| 久久精品无码av| 久久夜色撩人精品国产| 久久亚洲中文字幕精品一区| 久久久久久狠狠丁香| 久久综合综合久久97色| 色综合久久久久网| 久久影院亚洲一区| 伊人久久成人成综合网222| 亚洲一区精品伊人久久伊人|