算法——Boyer–Moore–Horspool algorithm(翻譯版)

舍卒保車,壯士斷腕。(描述時空權衡) 

題目描述

Boyer-Moore字符串搜索算法是一種高效的字符串搜索算法.它是由鮑勃·博耶和J·斯特羅瑟·摩爾於1977年開發的。該算法預處理正在搜索的目標字符串(鍵),但不預處理要搜索的字符串(與某些算法不同,這些算法預處理要搜索的字符串,然後可以通過反覆搜索來攤銷預處理的開銷)。Boyer-Moore算法的執行時間實際上可以是次線性的:它不需要實際檢查要搜索的字符串的每個字符,而是跳過其中的一些字符。通常,當搜索的密鑰變得更長時,算法會變得更快。它的效率源於這樣一個事實,即每次試圖在搜索字符串和它正在搜索的文本之間找到匹配項時,它都會使用從該嘗試中獲得的信息來排除字符串無法匹配的文本中儘可能多的位置。

 算法是如何工作的

當人們第一次遇到Boyer-Moore算法時,人們經常會感到驚訝的是,它的驗證--它試圖檢查某個特定位置是否存在匹配--向後工作。例如,如果它在文本開頭開始搜索“Anpanman”一詞,它會檢查文本的第八個位置,看看它是否包含“N”。如果它找到了“N”,它會移動到第七個位置,看它是否包含單詞的最後一個“A”,等等,直到它檢查文本的第一個位置是否爲“A”爲止。當我們考慮如果驗證失敗時,Boyer-Moore採取這種反向方法的原因更清楚--例如,如果我們在第八位沒有找到“N”,而是找到了一個“X”。“X”沒有出現在“Anpanman”中的任何地方,這意味着在文本的開頭--或者後面的七個位置--沒有匹配的搜索字符串,因爲所有這些都會落在“X”之間。在“X”之後。這解釋了爲什麼對於長度爲N的文本和長度爲M的固定模式,該算法的最佳情況性能是N/M:在最好的情況下,只需要檢查M字符中的一個。這也解釋了在某種程度上違背直覺的結果,即我們尋找的模式越長,算法通常就能越快地找到它。該算法預計算兩個表,以處理在每個失敗驗證中獲得的信息:一個表根據導致匹配嘗試失敗的字符的標識計算前面的幾個位置,以啓動下一個搜索;另一個表根據嘗試匹配失敗之前成功匹配的字符數進行類似計算(因爲這兩個表返回的結果表明在文本中“跳轉”有多遠,所以它們有時被稱爲“跳轉表”,這不應與計算機科學中跳轉表更常見的含義混淆。)。

第一個表

第一個表很容易計算:從查找字符串的最後一個字符開始,然後移動到第一個字符。每次向左移動時,如果您所在的字符不在表中,則添加它;它的移位值是它與最右邊字符之間的距離。所有其他字符都會收到與搜索字符串長度相等的計數。

 例子

對於字符串Anpanman,第一個表將如圖所示(爲了清晰起見,條目按添加到表中的順序顯示):(假定爲零的N基於右邊的第二個N,因爲我們只從字母m-1計算)。

 第一個表計算的移位量有時被稱爲“壞字符移位”[1]。

第二個表

第二個表更難計算:對於小於搜索字符串長度的每個i值,我們必須首先計算由搜索字符串的最後i個字符組成的模式,前面是對前面字符的錯誤匹配;然後我們首先將其與搜索模式對齊,並確定兩個模式匹配之前必須左移的部分模式必須移動的最少字符數。例如,對於搜索字符串Anpanman,表如下所示:(n表示任何不是N的字符)

 第二個表計算的移位量有時稱爲“好後綴移位”[2]或“(強)好後綴規則”。最初出版的Boyer-Moor算法[1]使用了更簡單、更弱的好後綴規則,其中上表中的每個條目都不需要對最左邊的字符進行錯誤匹配。這有時被稱爲“弱好後綴規則”,不足以證明Boyer-Moore在線性最壞情況下運行。

Boyer-Moore字符串搜索算法的性能

在最壞的情況下,要查找文本中的所有事件,需要進行大約3*N的比較,因此,無論文本是否包含匹配項,複雜度都是O(N)。這一證明應歸功於Richard Cole,見R.Cole,關於Boyer-Moore算法複雜性的嚴格限制,第二屆ACM-SIAM離散算法研討會會議記錄(1991)。這個證據花了幾年時間才確定。在該算法設計的那一年,1977年,最大的比較次數顯示不超過6*N;在1980年,它被證明不超過4*N,直到1991年Cole的結果。

輸入

字符串中只有兩行字符“ACGT”。第一行是字符串(<=102000),第二行是文本(<=700000)

輸出

字符串在文本中的位置否則輸出-1

樣例輸入

GGCCTCATATCTCTCT
CCCATTGGCCTCATATCTCTCTCCCTCCCTCCCCTGCCCAGGCTGCTTGGCATGG

 樣例輸出

6


題目鏈接 

解題

看到字超級多的題目不要慌,因爲大部分都沒有我們想象的那麼難,比如本題,大量的字數只是爲了解釋 Boyer-Moore-Horspool 算法的知識點,而本題真正要求的是在字符串匹配中,利用Boyer-Moore-Horspool算法,找出字符串在文本中的位置,未找到匹配項,則輸出-1.

本題的題目描述即Boyer-Moore-Horspool算法的描述,所以我把全文翻譯出來(現在網上翻譯技術很贊),以便讀者理解。

Horspool算法:

第一步:對於給定的長度爲len_str的模式和在模式及文本中用到的字母表,構造移動表;

第二步:將模式和文本的開始對齊;

第三步:重複下面的過程,直到發現了一個匹配子串或者模式到達了文本的最後一個字符以外。從模式的最後一個字符開始,比較模式和文本的相應字符,直到:要麼所有len_str個字符都匹配(然後停止),要麼遇到了一對不匹配的字符。在後一種情況下,如果c是當前文本中和模式的最後一個字符相對齊的字符,在從移動表的第c列中取出單元格 t(c) 的值,然後將模式沿着文本向右移動 t(c) 個字符的距離。

 

完整代碼

#include<iostream>
#include<cstring>
using namespace std;
int table[26];
int horspoolMatch(char str[],char text[]){
	int len_str = strlen(str);
	int len_text = strlen(text);
	for(int i = 0; i < len_str - 1; i ++){
		table[str[i] - 'A'] = len_str - i - 1;	
	}
	int p = len_str - 1;
	while(p < len_text){
		int k = 0;
		while(str[len_str - 1 - k] == text[p - k] && k <= len_str){
			k++;
		}
		if(k == len_str){
			return p - len_str + 1;
		}
		else p += table[text[p] - 'A'];
	}
	return -1;
}
int main(){
	char str[102000],text[700000];
	cin>>str>>text;
	cout<<horspoolMatch( str, text)<<endl;
	return 0;
}

上幾篇算法:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章