中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
字符串搜索算法小結(jié)(轉(zhuǎn))
因為在網(wǎng)上搜尋hash算法的知識,無意中又找到一些字符串搜索算法。 由于之前已經(jīng)學(xué)習(xí)過一些搜索算法,覺得應(yīng)該可以歸為一類。因此就寫一篇文章來記錄下學(xué)習(xí)的過程。

問題:

在一長字符串中找出其是否包含某子字符串。

首先當(dāng)然還是簡單算法,通過遍歷來檢索所有的可能:
Java代碼
 
  1. public static int naiveSearch(String content, String sub) {   
  2.     for(int i = 0; i < (content.length() - sub.length() + 1); i++) {   
  3.         boolean found = true;   
  4.         for(int j = 0 ; j < sub.length(); j++) {   
  5.             if(content.charAt(i + j) != sub.charAt(j)) {   
  6.                 found = false;   
  7.                 break;   
  8.             }   
  9.         }   
  10.            
  11.         if(found) return i;   
  12.     }   
  13.        
  14.     return -1;   
  15. }  

時間復(fù)雜度為 Θ((n-m+1) m)

Rabin–Karp,即hash檢索法:
Java代碼
 
  1. public static int rabinKarp(String content, String sub) {   
  2.     long hcontent = rshash(content.substring(0, sub.length()));   
  3.     long hsub = rshash(sub);   
  4.        
  5.     for(int i = 0; i < (content.length() - sub.length()); i++) {   
  6.         //hcontent = rshash(content.substring(i, sub.length() + i));   
  7.   
  8.         if(hsub == hcontent) {   
  9.             if(sub.equals(content.substring(i, i + sub.length()))) {   
  10.                 return i;   
  11.             }   
  12.         }   
  13.            
  14.         hcontent = newhash(content, hcontent, i + 1, sub.length());   
  15.     }   
  16.        
  17.     return -1;   
  18. }   
  19.   
  20. private static long rshash(String str)     
  21. {   
  22.    int a = 63689;   
  23.    long hash = 0;   
  24.       
  25.    for(int i = 0; i < str.length(); i++)   
  26.    {   
  27.       hash += a * str.charAt(i);   
  28.    }    
  29.    return hash;   
  30. }   
  31.   
  32. private static long newhash(String str, long previous, int i, int length)     
  33. {   
  34.    int a = 63689;   
  35.       
  36.    long minHash = str.charAt(i - 1) * a;   
  37.       
  38.    long plusHash = str.charAt(i + length - 1) * a;   
  39.       
  40.    return (previous - minHash + plusHash);   
  41. }  

這個算法的核心思想是,通過hash值,我們可以一次匹配一整條字串,速度上要快很多。
關(guān)鍵: 選擇這樣一種hash算法,使得從前一個hash值到后一個hash值僅需要常量的步驟。

我這里實現(xiàn)的hash算法可以做到這點,但是有效性并不高,應(yīng)該還有其他的hash算法可以更好了減少沖突的發(fā)生。

KMP算法
KMP算法說簡單也不簡單,說復(fù)雜也不復(fù)雜。只要你理解了它的核心思想,代碼量其實非常少。可是想要解釋它的思想,卻也不是一件容易的事情。

考慮再三,還是覺得自己無法勝任這個解釋工作,于是找了一篇自己認(rèn)為解釋KMP算法比較透徹的文章,翻譯出來,看看大家有沒有更哈的建議。

KMP algorithm
http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm

實例
為了解釋該算法的細(xì)節(jié),我們首先利用一個實例來把算法的步驟過一遍。在這個過程中的任意時間點,該算法的狀態(tài)都由兩個變量來決定, m和i。 m代表在S中,某個對于W(pattern)匹配的起始位置。 i代表在W中的當(dāng)前正在進行匹配工作的位置。我們來描述一下當(dāng)算法開始時的狀態(tài):
             1         2 
m: 01234567890123456789012
S: ABC ABCDAB ABCDABCDABDE
W: ABCDABD
i: 0123456

我們首先從0位開始匹配W和S中平行的字符串,如果匹配,則前進到下一位。然而當(dāng)我們到第四步的時候,我們發(fā)現(xiàn)S[3]是空格而W[3]=‘D’,出現(xiàn)了第一個不匹配。在傳統(tǒng)的模式匹配算法中,接下來我們應(yīng)該從S[1]的位置重新開始匹配。然而,如果我們仔細(xì)觀察,在S的0到3位中(也就是我們剛剛進行過匹配成功的位),除了0位,其它都沒有‘A‘出現(xiàn)過。而假設(shè)某字符串中有和W匹配的子串,那么這個子串必須是以’A‘開頭的。因此,我們可以確定,S的0到3位中,都不可能存在這樣的子串,于是我們決定從S的4位中重新找起。也就是說,m=4, i=0.

             1         2 
m: 01234567890123456789012
S: ABC ABCDAB ABCDABCDABDE
W:     ABCDABD
i:     0123456


此時,我們獲得了一個幾乎匹配的“ABCDAB”,然后在W[6](S[10])這個位置上,我們又出現(xiàn)了一個不匹配。于是,我們應(yīng)該繼續(xù)擴大m的值去尋找下一個可能的匹配。那么m的下一個值應(yīng)該設(shè)置為多少呢?

整個算法的核心就在于此,我們可以從不匹配的位置開始,即m=10,然后這并不是一個正確的選擇,我們發(fā)先在S的4到10位中,第8位也是‘A’。因此,如果我們從第十位開始繼續(xù)找起的話,有可能就錯過了某個匹配。

S中第八位的‘A’和第九位的‘B’,分別跟W的第0第1位相匹配。KMP算法對此的處理是,新的m=8(即首位匹配的值),新的i=2(因為前兩位根據(jù)統(tǒng)計,已經(jīng)是匹配好的了)。然后我們從S的m+i開始匹配W的i位。


             1         2 
m: 01234567890123456789012
S: ABC ABCDAB ABCDABCDABDE
W:         ABCDABD
i:         0123456

跟第一步類似,我們在i=2就出錯了,下一步我們應(yīng)該跳轉(zhuǎn)到哪里呢?當(dāng)然是m=11,i=0:

             1         2 
m: 01234567890123456789012
S: ABC ABCDAB ABCDABCDABDE
W:            ABCDABD
i:            0123456

此時,我們又在m=17的位置上出錯了,根據(jù)第二步的解釋,我們這次跳到m=15而i=2:

             1         2 
m: 01234567890123456789012
S: ABC ABCDAB ABCDABCDABDE
W:                ABCDABD
i:                0123456

找到該模式,算法結(jié)束,返回m的值15.

部分匹配表
如果我們剛才的分析那樣,整個匹配算法的核心就在于,當(dāng)某次匹配過程出現(xiàn)不匹配的值時,如何尋找下一個做匹配的位置(這里的位置包括兩個概念,即起始位置和我們應(yīng)該從哪個值開始做匹配)。這樣的值當(dāng)然是越大越好,因為選擇的下一個匹配位置越大,我們跳過的值就越多,整個算法就越快。

如果單看我們之前的分析,好像這個確定下一個匹配位置的工作關(guān)系到S和W兩張表。其實不是這樣的,我們只需要對W進行一個預(yù)處理,就可以做到這點

還是來看,當(dāng)W是“ABCDABD”這樣一個字串時。我們會發(fā)現(xiàn)除了起始位置是‘A’以外,4位的值也是‘A’,那么如果我們在某次匹配時,匹配到了W的第4位,那么下一次做匹配查找時,就應(yīng)當(dāng)從W第4位對應(yīng)的那個字符開始:
m     123456
S ... ABCDAX...
W     ABCDABD
i     0123456
因為我們已經(jīng)知道S[5]和W[4]是匹配的了,那么其實就不需要再匹配一次了。因此匹配的起始位置是m=5,但是應(yīng)當(dāng)從i=1那里開始進行匹配。

如果是這樣的一個情況呢?
m     1234567
S ... ABCDABX..
W     ABCDABD
i     0123456
同樣的道理,匹配的起始位置依然是m=5,但是應(yīng)當(dāng)從i=2開始匹配。

下面給出求出當(dāng)從任一位出現(xiàn)不匹配是,應(yīng)該從哪里開始從新匹配的算法:
Java代碼
 
  1. private static void next(char[] input, int[] table) {   
  2.     int pos = 2;   
  3.     int cnd = 0;   
  4.        
  5.     table[0] = -1;   
  6.     table[1] = 0;   
  7.        
  8.     while(pos < input.length) {   
  9.         if(input[pos - 1] == input[cnd]) {   
  10.             table[pos] = cnd + 1;   
  11.             pos++;   
  12.             cnd++;   
  13.         } else if(cnd > 0) {   
  14.             cnd = table[cnd];   
  15.         } else {   
  16.             table[pos] = 0;   
  17.             pos++;   
  18.         }   
  19.     }   
  20. }  



既然已經(jīng)得到了這樣一個表,那么寫出整個KMP算法也不是什么難事了:

Java代碼
 
  1. private static void next(char[] input, int[] table) {   
  2.     int pos = 2;   
  3.     int cnd = 0;   
  4.        
  5.     table[0] = -1;   
  6.     table[1] = 0;   
  7.        
  8.     while(pos < input.length) {   
  9.         if(input[pos - 1] == input[cnd]) {   
  10.             table[pos] = cnd + 1;   
  11.             pos++;   
  12.             cnd++;   
  13.         } else if(cnd > 0) {   
  14.             cnd = table[cnd];   
  15.         } else {   
  16.             table[pos] = 0;   
  17.             pos++;   
  18.         }   
  19.     }   
  20. }  


最后兩個算法分別是BM算法和有限自動機算法。昨天我花了一天的時間研究BM算法,對算法的本質(zhì)有了一定的了解,但是對于如何編碼還是有點困惑。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
常用的排序算法(包括冒泡排序,選擇排序,插入排序,希爾排序,快速排序)
Strassen矩陣乘法
字節(jié)數(shù)組轉(zhuǎn)成16進制
web信息的搜集---StrFun.h+StrFun.cpp
java排序算法
字符串模式匹配
更多類似文章 >>
生活服務(wù)
熱點新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服