日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

字符串匹配算法知多少?

發布時間:2024/8/1 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 字符串匹配算法知多少? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • BF算法
    • RK算法
    • 編輯器中的全局替換方法:BM算法
      • 壞字符
      • 好后綴規則
      • 代碼實現
    • KMP算法

一說到字符串匹配算法,不知道會有多少小伙伴不由自主的想起那個kmp算法呢?

想到是很正常的,誰讓它那么優秀呢。


BF算法

不要被事物的表面現象所迷惑,這個算法全稱:Brute Force,有個拉風的中文名:暴力匹配算法。

能想明白了吧。

如果模式串長度為 m,主串長度為 n,那在主串中,就會有 n-m+1 個長度為 m 的子串,我們只需要暴力地對比這 n-m+1 個子串與模式串,就可以找出主串與模式串匹配的子串。

1、從頭開始往后遍歷匹配; 2、遇上不對了,就回頭,把子串和主串的匹配頭后移一位 3、重復以上。直到找到或確定找不到。

復雜度很高啊,但是在實際開發中也是比較常用的。為什么呢?
真當天天都有成千上萬個字符的主串讓我們去匹配嗎?一般都比較短,而且,統計意義上,算法執行效率不會真的到M*N的地步。

理論還是要結合實際的。

還有另一個原因,就是它好寫。當然kmp現在更好寫,因為封裝好了。
我說的是類似的場景,沒有封裝好的函數時候,好寫,好改。


RK算法

RK 算法的思路是這樣的:我們通過哈希算法對主串中的 n-m+1 個子串分別求哈希值,然后逐個與模式串的哈希值比較大小。如果某個子串的哈希值與模式串相等,那就說明對應的子串和模式串匹配了(這里先不考慮哈希沖突的問題,后面我們會講到)。因為哈希值是一個數字,數字之間比較是否相等是非常快速的,所以模式串和子串比較的效率就提高了。

有沒有方法可以提高哈希算法計算子串哈希值的效率呢?

我們假設要匹配的字符串的字符集中只包含 K 個字符,我們可以用一個 K 進制數來表示一個子串,這個 K 進制數轉化成十進制數,作為子串的哈希值。

比如要處理的字符串只包含 a~z 這 26 個小寫字母,那我們就用二十六進制來表示一個字符串。我們把 a~z 這 26 個字符映射到 0~25 這 26 個數字,a 就表示 0,b 就表示 1,以此類推,z 表示 25。

這里有一個小細節需要注意,那就是 26^(m-1) 這部分的計算,我們可以通過查表的方法來提高效率。我們事先計算好 26^0、26^1、26^2……26^(m-1),并且存儲在一個長度為 m 的數組中

模式串哈希值與每個子串哈希值之間的比較的時間復雜度是 O(1),總共需要比較 n-m+1 個子串的哈希值,所以,這部分的時間復雜度也是 O(n)。所以,RK 算法整體的時間復雜度就是 O(n)。

但是呢,還有一個很致命的問題,叫做數值過大。
以冪增的速度是非常快的,用不了多久int就hold不住了啊,那要怎么辦?難道我們前面所做的努力都白費了?

其實不然。
比方說我們可以改乘為加,當我們匹配到一樣的哈希值的時候,再打開子串進行比對,因為相加的話是會有哈西沖突的。

此外,我們還可以加點優化,一邊對主串構建,一邊對子串進行匹配,如果一樣的話就不繼續計算后面的hash了。
該省的時候就要省,該花的時候就要花。


編輯器中的全局替換方法:BM算法

用過嗎?比方說要在我這篇博客里找出全部的“主串”這個詞,有沒有想過其底層的原理?

這是一個性能優于KMP的算法。

壞字符

BM 算法的匹配順序比較特別,它是按照模式串下標從大到小的順序,倒著匹配的。

我們從模式串的末尾往前倒著匹配,當我們發現某個字符沒法匹配的時候。我們把這個沒有匹配的字符叫作壞字符(主串中的字符)

這時候該如何操作呢?我們去子串中尋找這個壞字符,如果找到了,就讓兩個字符的位置對上,繼續往后,如果沒有找到,就將整個子串移動到壞字符后面。

很顯然,這會兒沒找到。

接下來該怎么滑呢?又是個壞字符。
但是在子串中找到了那個壞字符,那就將兩個字符的位置對上。

模式串中有對應的壞字符時,讓模式串中 最靠右 的對應字符與壞字符相對。

但是呢,用這個規則還是不太夠用的,有些個特殊情況吧,它會導致不但不會向后滑動模式串,還有可能會倒推、

比如說主串:kkkkkkkkkkkkkkkkkk,模式串是 akk


好后綴規則

如果模式串中存在已經匹配成功的好后綴,則把目標串與好后綴對齊,然后從模式串的最尾元素開始往前匹配。

如果無法找到匹配好的后綴,找一個匹配的最長的前綴,讓目標串與最長的前綴對齊:

如果完全不存在和好后綴匹配的子串,則右移整個模式串


代碼實現

難頂,我一定會回來的

// a,b 表示主串和模式串;n,m 表示主串和模式串的長度。 public int bm(char[] a, int n, char[] b, int m) {int[] bc = new int[SIZE]; // 記錄模式串中每個字符最后出現的位置generateBC(b, m, bc); // 構建壞字符哈希表int[] suffix = new int[m];boolean[] prefix = new boolean[m];generateGS(b, m, suffix, prefix);int i = 0; // j 表示主串與模式串匹配的第一個字符while (i <= n - m) {int j;for (j = m - 1; j >= 0; --j) { // 模式串從后往前匹配if (a[i+j] != b[j]) break; // 壞字符對應模式串中的下標是 j}if (j < 0) {return i; // 匹配成功,返回主串與模式串第一個匹配的字符的位置}int x = j - bc[(int)a[i+j]];int y = 0;if (j < m-1) { // 如果有好后綴的話y = moveByGS(j, m, suffix, prefix);}i = i + Math.max(x, y);}return -1; }// j 表示壞字符對應的模式串中的字符下標 ; m 表示模式串長度 private int moveByGS(int j, int m, int[] suffix, boolean[] prefix) {int k = m - 1 - j; // 好后綴長度if (suffix[k] != -1) return j - suffix[k] +1;for (int r = j+2; r <= m-1; ++r) {if (prefix[m-r] == true) {return r;}}return m; }

KMP算法

【C++】算法集錦(10)通俗講kmp算法

總結

以上是生活随笔為你收集整理的字符串匹配算法知多少?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。