字串匹配
1.bf
brute force的縮寫,也叫做暴力匹配演算法,或者樸素匹配演算法。主串和模擬串
假設從a串(長度為n)中查詢b串(長度為m),所以n>m
樸素匹配演算法的核心思想就是:在主串中,檢查起始位置分別為0、1、2…n-m且長度為m的n-m+1個字串,看有沒有和模擬串匹配的。
最壞情況的時間複雜度為o(n*m)
但是實際開發中確實乙個比較常用的字串匹配演算法:
2.rk
rabin-karp bf演算法的公升級版本。因為bf演算法子串和主串中比較的時候,是乙個字元乙個字元進行對比的所以效率比較低。rk演算法對他進行了公升級,對n-m+1個字串分別進行求hash值,然後和子串的hash值做比較。然後根據特定的情況去制定特定的hash演算法,還需要考慮到雜湊衝突的情況怎麼處理等等。效率事要比bf高,但是也是存在時間複雜度退化的問題,最主要的就是hash演算法的設計以及雜湊衝突的解決。
hash演算法的設計技巧
3.bm演算法
bm演算法的核心思想:其實非常簡單,bf和rk都是匹配字串的時候都是一位一位向後邊移動的,bm演算法其實就是在找大到一些規律可以跳過一些肯定不會匹配的情況,也就是說一次向後邊移動很多位。bm演算法包含兩種情況:
不管是壞字元原則還是好字尾原則其實都是求沒有匹配到字串情況下最佳的後移步數。
壞字元原則(bad character rule)
壞字元原則,從後向前比較主串和模擬串的字元值,知道出現第乙個不相等的值為止,記錄下主串對應的字元值即為壞字元,對應在模擬串的索引為j,然後再模擬串中繼續尋找等於壞字元的索引值記為i,要移動的步數step=j-i(當模擬串沒有找到壞字元的時候i=-1)。如果壞字元在模擬串中出現多次,為了保證移動步數的正確性,選取最後一次出現的索引為準。翻譯成**如下:
1.首先是乙個雜湊演算法
把模擬串雜湊在陣列bc中,值就是對應模擬串的索引數,查詢的時候通過壞字元的asicc值進行查詢,不等於-1,說明模擬串中存在壞字元。
/**
* * @param b 模擬串
* @param bc 模擬串對應的雜湊表
* @param m 模擬串的長度
*/private
static
void
generatebc
(char
b,int[
] bc,
int m)
//2.將模擬串雜湊在陣列bc中,值就是對應模擬串的索引數
for(
int i =
0; i < m; i++
)}
2.第二步就是壞字元原則的演算法**了:(注釋就直接寫在**裡了)
/**
* 僅僅只考慮壞字元規則
* 其實演算法很簡單 就是 比較從後向前與主串進行比較 ,找出壞字串的位置 然後計算 查詢的後移數 重新進行查詢,但是這種
* 查詢存在隱患會出現 後移位數為負的情況 這就需要好字尾規則了。
* @param a 主串
* @param n 主串長度
* @param b 模擬串
* @param m 模擬串長度
* @return
*/public
intbmjustbadrule
(char
a,int n,
char
b,int m)
if(j<0)
return i;
i = i+
(j-(bc[
(int
)a[i+j]])
);//(j-(bc[(int)a[i+j]])即為本次需要移動的步數)
}return-1
;}
壞字元原則的原理如果理解了**的實現其實很簡單。其中把模擬串的字元雜湊在乙個陣列中,主要是為了提高查詢壞字元出現在模擬串位置的效率的提高。最好的時間複雜度為o(n/m)壞字串原則在一定的情況下會出現計算出的步數為負數的情況例如,***y和*********的情況。所以此時出現了另外乙個原則好字尾原則。
好字尾原則(good subfix shift)
好字尾就是壞字元之後主串中和模擬串中匹配的字串,就叫做好字尾串。例如 abbbccc中尋找。cbbb。 bbb就是乙個好字尾串。
好字尾原則存在兩種情況
好字尾串也是屬於模擬串的乙個字尾子串。
所以我們的所有操作都可以通過模擬子串來進行。
用乙個陣列suffix來記錄模擬子串的字尾串和模擬子串的匹配情況,其中suffix的索引即為字尾子串的長度,值即為模擬子串的首個字元的索引值。還需要乙個prefix進行記錄好字尾字串和模擬串的字首子串匹配的最大字尾子串。
例如 模擬串為:d b c d b c
-字尾子串-
-長度-
-suffix-
-prefix-c1
suffix[1]=2
falsebc2
suffix[2]=1
false
dbc3
suffix[3]=0
true
cdbc
4suffix[4]=-1
false
bcdbc
5suffix[5]=-1
false
suffix和prefix的陣列的計算**如下:
/**
* * @param b 表示模擬串
* @param m 表示長度
* @param suffix
* @param prefix
*/private
static
void
generategs
(char
b,int m,
int[
] suffix,
boolean
prefix)
//2.賦值suffix和prefix
for(
int i =
0; i < m -
1; i++)if
(j==-1
)prefix[k]
=true;}
}
然後完善壞字元原則的**如下:
/**
* 分為兩種規則
* 1.壞字元規則
* 2.好字尾規則
* @param a
* @param n
* @param b
* @param m
* @return
*/public
static
intbm
(char
a,int n,
char
b,int m)
if(j==-1
)return i;
//匹配成功返回主串與模擬串第乙個字元的位置
int x =
(j- bc[
(int
) a[i+j]])
;//b.找到好字尾規則的移動位置
int[
] suffix =
newint
[m];
boolean
prefix =
newboolean
[m];
generategs
(b,m,suffix,prefix)
;//判斷是否有好字尾
int y =0;
if(ji = i +math.
max(x,y);}
return-1
;}/** *
* @param j
* @param m 模擬串的長度
* @param suffix 模擬子串的長度就是 他的索引 然後子串在模擬串字首串中對應的索引就為陣列的值 suffix[x]=-1 suffix[x]!=-1
* @param prefix
* @return
*/private
static
intmovegs
(int j,
int m,
int[
] suffix,
boolean
prefix)
return m;
}
字串匹配演算法 字串匹配演算法總覽
字串匹配在文字處理裡非常重要,我們採用簡潔的python 把以下演算法一一實現並講解。樸素演算法 algorithm rabin karp 演算法 有限自動機演算法 finite automation knuth morris pratt 演算法 kmp algorithm boyer moore ...
字串匹配演算法
首先引用一下另一篇文章中對字串匹配的介紹 字串匹配指的是從文字中找出給定字串 稱為模式 的乙個或所有出現的位置。本文的演算法一律輸出全部的匹配位 置。模式串在 中用x m 來表示,文字用y n 來,而所有字串都構造自乙個有限集的字母表 其大小為 根 據先給出模式還是先給出文字,字串匹配分為兩類方法 ...
字串匹配演算法
平常操作文字的時候,經常需要操作對字串進行操作。而字串中最重要的一種操作就叫匹配,字串的匹配演算法很多,人們最熟悉的莫過於kmp演算法了。今天就來談一談一些字串匹配演算法。先來說說大名鼎鼎的kmp演算法,這個演算法出現在無數的資料結構與演算法書上面。它的策略很簡單 當模式串第k個字元不匹配主串中第s...