漫畫:什麼是字符串匹配算法?

2020-12-16 CSDN

————— 第二天 —————

什麼意思呢?讓我們來舉一個例子:

在上圖中,字符串B是A的子串,B第一次在A中出現的位置下標是2(字符串的首位下標是0),所以返回 2。

我們再看另一個例子:

在上圖中,字符串B在A中並不存在,所以返回 -1。

為了統一概念,在後文中,我們把字符串A稱為主串,把字符串B稱為模式串。

小灰的想法簡單粗暴,讓我們用下面的例子來演示一下:

第一輪,我們從主串的首位開始,把主串和模式串的字符逐個比較:

顯然,主串的首位字符是a,模式串的首位字符是b,兩者並不匹配。

第二輪,我們把模式串後移一位,從主串的第二位開始,把主串和模式串的字符逐個比較:

主串的第二位字符是b,模式串的第二位字符也是b,兩者匹配,繼續比較:

主串的第三位字符是b,模式串的第三位字符也是c,兩者並不匹配。

第三輪,我們把模式串再次後移一位,從主串的第三位開始,把主串和模式串的字符逐個比較:

主串的第三位字符是b,模式串的第三位字符也是b,兩者匹配,繼續比較:

主串的第四位字符是c,模式串的第四位字符也是c,兩者匹配,繼續比較:

主串的第五位字符是e,模式串的第五位字符也是e,兩者匹配,比較完成!

由此得到結果,模式串 bce 是主串 abbcefgh 的子串,在主串第一次出現的位置下標是 2:

以上就是小灰想出的解決方案,這個算法有一個名字,叫做BF算法,是Brute Force(暴力算法)的縮寫。

上圖的情況,在每一輪進行字符匹配時,模式串的前三個字符a都和主串中的字符相匹配,一直檢查到模式串最後一個字符b,才發現不匹配:

這樣一來,兩個字符串在每一輪都需要白白比較4次,顯然非常浪費。

假設主串的長度是m,模式串的長度是n,那麼在這種極端情況下,BF算法的最壞時間複雜度是O(mn)。

————————————

比較哈希值是什麼意思呢?

用過哈希表的朋友們都知道,每一個字符串都可以通過某種哈希算法,轉換成一個整型數,這個整型數就是hashcode:

hashcode = hash(string)

顯然,相對於逐個字符比較兩個字符串,僅比較兩個字符串的hashcode要容易得多。

給定主串和模式串如下(假定字符串只包含26個小寫字母):

第一步,我們需要生成模式串的hashcode。

生成hashcode的算法多種多樣,比如:

按位相加

這是最簡單的方法,我們可以把a當做1,b當做2,c當做3......然後把字符串的所有字符相加,相加結果就是它的hashcode。

bce = 2 + 3 + 5 = 10

但是,這個算法雖然簡單,卻很可能產生hash衝突,比如bce、bec、cbe的hashcode是一樣的。

轉換成26進位數

既然字符串只包含26個小寫字母,那麼我們可以把每一個字符串當成一個26進位數來計算。

bce = 2*(26^2) + 3*26 + 5 = 1435

這樣做的好處是大幅減少了hash衝突,缺點是計算量較大,而且有可能出現超出整型範圍的情況,需要對計算結果進行取模。

為了方便演示,後續我們採用的是按位相加的hash算法,所以bce的hashcode是10:

第二步,生成主串當中第一個等長子串的hashcode。

由於主串通常要長於模式串,把整個主串轉化成hashcode是沒有意義的,只有比較主串當中和模式串等長的子串才有意義。

因此,我們首先生成主串中第一個和模式串等長的子串hashcode,

即abb = 1 + 2 + 2 = 5:

第三步,比較兩個hashcode。

顯然,5!=10,說明模式串和第一個子串不匹配,我們繼續下一輪比較。

第四步,生成主串當中第二個等長子串的hashcode。

bbc = 2 + 2 + 3 = 7:

第五步,比較兩個hashcode。

顯然,7!=10,說明模式串和第二個子串不匹配,我們繼續下一輪比較。

第六步,生成主串當中第三個等長子串的hashcode。

bce= 2 + 3 + 5 = 10:

第七步,比較兩個hashcode。

顯然,10 ==10,兩個hash值相等!這是否說明兩個字符串也相等呢?

別高興的太早,由於存在hash衝突的可能,我們還需要進一步驗證。

第八步,逐個字符比較兩字符串。

hashcode的比較只是初步驗證,之後我們還需要像BF算法那樣,對兩個字符串逐個字符比較,最終判斷出兩個字符串匹配。

最後得出結論,模式串bce是主串abbcefgh的子串,第一次出現的下標是2。

什麼意思呢?讓我們再來看一個例子:

上圖中,我已知子串abbcefg的hashcode是26,那麼如何計算下一個子串,也就是bbcefgd的hashcode呢?

我們沒有必要把子串的字符重新進行累加運算,而是可以採用一個更簡單的方法。由於新子串的前面少了一個a,後面多了一個d,所以:

新hashcode = 舊hashcode - 1 + 4 = 26-1+4 = 29

再下一個子串bcefgde的計算也是同理:

新hashcode = 舊hashcode - 2 + 5 = 29-2+5 = 32

publicstaticintrabinKarp(String str, String pattern){//主串長度int m = str.length();//模式串的長度int n = pattern.length();//計算模式串的hash值int patternCode = hash(pattern);//計算主串當中第一個和模式串等長的子串hash值int strCode = hash(str.substring(0, n));//用模式串的hash值和主串的局部hash值比較。//如果匹配,則進行精確比較;如果不匹配,計算主串中相鄰子串的hash值。for (int i=0; i<m-n+1; i++) {if(strCode == patternCode && compareString(i, str, pattern)){return i; }//如果不是最後一輪,更新主串從i到i+n的hash值if(i<m-n){ strCode = nextHash(str, strCode, i, n); } }return-1;}privatestaticinthash(String str){int hashcode = 0;//這裡採用最簡單的hashcode計算方式://把a當做1,把b當中2,把c當中3.....然後按位相加for(int i = 0; i < str.length(); i++) { hashcode += str.charAt(i)-'a'; }return hashcode;}privatestaticintnextHash(String str, int hash, int index, int n){ hash -= str.charAt(index)-'a'; hash += str.charAt(index+n)-'a';return hash;}privatestatic boolean compareString(int i, String str, String pattern){ String strSub = str.substring(i, i+pattern.length());return strSub.equals(pattern);}publicstaticvoidmain(String[] args){ String str = "aacdesadsdfer"; String pattern = "adsd"; System.out.println("第一次出現的位置:" + rabinKarp(str, pattern));}

本文為程式設計師小灰(ID:chengxuyuanxiaohui)投稿。

相關焦點

  • 漫畫:如何優化 「字符串匹配算法」?
    BF算法是如何工作的?正如同它的全稱BruteForce一樣,BF算法使用簡單粗暴的方式,對主串和模式串進行逐個字符的比較。比如給定主串和模式串如下:當模式串挪動到某個合適位置,逐個字符比較,發現每一位字符都是匹配時,比較結束:
  • 字符串匹配的Rabin-Karp算法
    字符串匹配,是文本編輯器的常用算法。例如我常用的vim編輯器,它的s命令就可以查找文件裡的某個字符串並替換:%s/int/long/g就可以把所有的int關鍵字替換為long。sed、gawk等程序也需要這個功能,gawk會查找指定的分隔符,sed的s命令與vim的差不多。
  • Java數據結構與算法——字符串匹配相關算法
    Java裡用的是indexOf函數,其底層就是字符串匹配算法.其中字符串匹配算法主要包括:1. BF(暴力匹配)算法1.1概念和原理Brute Force叫作暴力匹配算法,也叫樸素匹配算法。其主要實現原理就是 在主串中,檢查起始位置分別是 0、1、2…n-m 且長度為 m 的 n-m+1 個子串,看有沒有跟模式串匹配的。
  • 字符串匹配算法之 AC 自動機
    我們經常用的字符串方法indexOf,都是判定兩個字符串的包含關係,底層使用類似KMP,BM, Sunday這樣的算法。如果我們要判斷一個長字符串是否包含多個短字符串呢?比如在一篇文章找幾個敏感詞,在DNA串中找幾個指定的基因對pattern進行預處理,如果我們的模式串存在多個,則不適合了,我們就需要用到一種多模式匹配算法。最著名的多模式匹配算法為AC自動機,它是由貝爾實驗室的兩位研究人員 Alfred V.
  • "暴力"字符匹配算法的C語言實現
    本篇文章主要是為講解高效字符匹配算法的一則預告文,跟大家講講暴力字符匹配算法以及匹配算法在通信中如何使用。bug菌所說的暴力匹配算法就是C標準庫函數strstr(),如果你還沒有使用過或者沒有聽到過這個函數,那就有點.。
  • 漫畫:什麼是KMP算法?
    而BM算法解決了這一問題。它藉助「壞字符規則」和「好後綴規則」,在每一輪比較時,讓模式串儘可能多移動幾位,減少無謂的比較。利用BM算法,上面的主串和模式串匹配只需要比較三輪:KMP算法的整體思路KMP算法的整體思路是什麼樣子呢?
  • 算法連載之求解不含有重複字符的最長子串長度
    問題給定一個字符串,找出其中不含有重複字符的最長子串長度。分析程序,匹配在給定字符串中是否有重複字符isRepeating函數的時間複雜度是O(n)。因此,完成算法的時間複雜度是O(n);空間複雜度是O(min(n, m)),其中n是字符串的長度,m是相異字符的數量。
  • php字符串函數
    ,implode()函數的別名levenshtein — 計算兩個詞的差別大小localeconv — 獲取數字相關的格式定義ltrim — 去除字符串左側的空白或者指定的字符md5_file — 將一個文件進行MD5算法加密md5 — 將一個字符串進行MD5算法加密metaphone — 判斷一個字符串的發音規則
  • 經典leetcode算法題分享(字符串)
    那麼應該採取什麼方法校驗呢?我馬上想到的是通過成對成對地刪除有效的括號,從最裡面一直往外層刪除,最後能刪除完,變成空字符串就代表是有效括號返回true,否則返回false。關鍵是怎麼找到最裡層的有效括號,其實就是找到第一個右括號,然後判斷左邊的括號是否能匹配,能匹配的話就是最裡層的有效括號,然後刪除掉。刪除後,因為字符串的長度變短了兩位,所以我們把指針往左邊移動兩位即可。這樣遍歷下來,就只會遍歷一次。最後還是判斷字符串的長度。
  • 字符串: KMP是時候上場了(一文讀懂系列)
    所以叫做KMPKMP有什麼用KMP主要應用在字符串匹配上。KMP的主要思想是「當出現字符串不匹配時,可以知道一部分之前已經匹配的文本內容,可以利用這些信息避免從頭再去做匹配了。」可以看出,文本串中第六個字符b 和 模式串的第六個字符f,不匹配了。如果暴力匹配,會發現不匹配,此時就要從頭匹配了。但如果使用前綴表,就不會從頭匹配,而是從上次已經匹配的內容開始匹配,找到了模式串中第三個字符b繼續開始匹配。
  • V19.使用分組和結果屬性值匹配目標字符串
    一、題目如下圖,從A1單元格中一次性提取序號姓名、序號和姓名並分三列獨立顯示:顯示結果如下:二、解題思路首先分析A1單元格中字符串的特點:3.又因為需要分兩列單獨顯示序號(不需要點號)和姓名,故此就需要用到分組的方法,分組的方法就是用圓括號()把匹配目標字符串的表達式括起來。4.Pattern的屬性值為:.Pattern = "(\d+)\.+?\s*([一-龢]+)(\s+|(?!.))"
  • php字符串函數匯總
    str_pad — 使用另一個字符串填充字符串為指定長度str_repeat — 重複一個字符串str_replace — 子字符串替換str_rot13 — 對字符串執行 ROT13 轉換str_shuffle — 隨機打亂一個字符串str_split — 將字符串轉換為數組str_word_count
  • 在字符串中搜索標記--labview字符串函數之一
    一直未能找到合適的字符串函數來解析出來有效數據,而昨天恰恰看到了這樣一個字符串函數——在字符串中搜索標記。默認值為0,即字符串的起始位置。運算符是字符串數組,如輸入字符串包含字符串數組,即使它們沒有被分隔符分隔,函數仍將其視為標記。如輸入字符串的一部分匹配多個運算符,函數將把最長的匹配作為標記。例如,如>、=和>=被定義為運算符,輸入字符串4>=0將生成>=作為下一個標記字符串,偏移量為1。
  • 漫畫:探索字符串匹配系列 第一講(Sunday 是個啥玩意)
    了解這些基本概念,回到這個算法。Sunday匹配不是說這人在周末發現了這個算法,而是這人名字叫星期天(可能父母總加班,所以起了這麼個名)。聽起來牛叉的不得了,其實是個啥意思:假若我們的目標串為:Here is a little Hao模式串為:little一般來講,字符串匹配算法第一步,都是把目標串和模式串對齊。不管是KMP,BM,SUNDAY都是這樣。
  • Ruby 字符串(String)
    如果 obj 不是字符串,則返回 false,如果 str <=> obj,則返回 true,返回 0。7str =~ obj根據正則表達式模式 obj 匹配 str。返回匹配開始的位置,否則返回 false。8str =~ obj根據正則表達式模式 obj 匹配 str。
  • useful R 字符串函數
    正則表達式(Regular Expression)是一種匹配檢索模式,用於查詢符合一定規則的字符,想了解更多可以百度搜索《正則表達式30分鐘入門教程》,這分教程非常簡單,但是正則表達式實在是天書,如果不是專門幹這一項,了解一些基礎的概念和常見的寫法就可以了,比如什麼叫元字符,什麼叫轉義等等。
  • Sunday 匹配是啥?
    其核心思想是:在匹配過程中,模式串發現不匹配時,算法能跳過儘可能多的字符以進行下一步的匹配,從而提高了匹配效率。,字符串匹配算法第一步,都是把目標串和模式串對齊。而對於SUNDAY算法,我們從頭部開始比較,一旦發現不匹配,直接找到主串中位於模式串後面的第一個字符,即下面綠色的 「s」。(這裡說明一下,為什麼是找模式串後面的第一個字符。在把模式串和目標串對齊後,如果發現不匹配,那肯定需要移動模式串。問題是需要移動多少步。
  • 輕鬆理解什麼是KMP算法
    KMP算法 內部涉及到的數學原理與知識太多,本文只會對 KMP算法 的運行過程、 部分匹配表 、next數組 進行介紹,如果理解了這三點再去閱讀其它有關 KMP算法 的文章肯定能有個清晰的認識。以下的文字描述請結合視頻動畫來閱讀~定義Knuth-Morris-Pratt 字符串查找算法,簡稱為 KMP算法,常用於在一個文本串 S 內查找一個模式串 P 的出現位置。
  • 一招解決4道leetcode hard題,動態規劃在字符串匹配問題中的應用
    動態規劃的思路就是找到一個遞推的公式,由前往後或者由後往前來求解題目,在字符串匹配問題中,我們的基本的思想就是從前面開始,維護兩個指針,一個指針從前往後遍歷目標字符串,一個指針從前往後遍歷pattern字符串,並不斷判斷當前兩個指針前面的子串是否匹配。這個思想,很容易轉換成一張二維表格。我們要做的,就是找到這張二維表格的轉換關係或者說遞推公式。
  • 每日一道算法題,讓你的頭腦更活躍(沒有重複字符的最長子串)
    最近準備把算法慢慢的撿起來,所以準備日更一道算法題目,難度自然是由簡入難,所以同學們可以每天都來看看小編的更新。日更時間定在每晚20:00,希望大家多多關注啦。沒有重複字符的最長子串給定一個字符串,查找不重複字符的最長子字符串的長度。