整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          python數據結構與算法——模式匹配算法

          在經典的模式匹配問題中,我們給出了長度為n的文本字符串T和長度為m的模式字符P,并希望明確是否P是T的一個字串。如果是,則希望找到P在T中開始位置的最低索引j,比如T[j:j+m]和P匹配,或者從T中找到所有的P的開始位置索引。

          在本文中,我們介紹三種匹配算法,難度依次遞增。

          1.暴力窮舉法

          窮舉法是極其常用的一種算法,不止在匹配算法上,還在優化某些功能上也有涉及。

          窮舉法即為列舉出所有的可能情況,并加以逐一判斷。

          def find_brute(T, P):
              """Return the lowest index of T at which substring P begins (or else -1)"""
              n, m = len(T), len(P)   # Get length of T and P's
              for i in range(n-m+1):  # Because it can't be P after T[n-m+1:]
                  k = 0               # Record the index of P
                  while k < m and T[i + k] == P[k]:   # The match was incomplete and successful
                      k += 1
                  if k == m:          # Match successful
                      return i
              return -1

          這是一個簡單的暴力枚舉的匹配算法,判斷P是否是T的一個子串,是則返回第一次出現的索引,否則返回-1,算法優化在不改變代碼結構的基礎上,就是這里扣一點,那里扣一點。例如range函數的范圍我們給出了n-m+1,因此對于P長度越大,則性能優化最大。

          我們可以看到外層for循環至多執行了n-m+1次,內存while循環至多執行了m次,因此,該算法在最壞的情況下的運行時間是

          測試一下:

          T = "abcafgasdfwefacasdfe"
          P = "asd"
          print(find_brute(T, P))

          運行結果:

          2.Boyer-Moore算法

          Boyer-Moore算法的主要思想是通過增加兩個可能省時的啟發式算法來提升窮舉法的運行時間:

          1.鏡像啟發式(Looking-glass ):當測試P相對于T可能的位置時,可以從P的尾部開始比較,然后從后向前移動直到P的頭部。

          2.字幕跳躍啟發式(-jump ):在測試P在T中可能的位置時,有著相應模式字符P[k]的文本字符T[i] = c的不匹配情況按如下方法處理:如果P中任何位置都不包含c,則將P完全移動到T[i]之后,(因為它不能匹配P中任何一個字符);否則,直到P中出現字符c并與T[i]一致才移動P。

          def find_boyer_moore(T, P):
              """Return the lowest index of T at which substring P begins (or else -1)"""
              n, m = len(T), len(P)   # get length of T and P's
              if m == 0: return 0     # Return 0 if m's length is 0
              last = {}               # Create a dictionary for P
              for k in range(m):      # Add each character position of P to the dictionary
                  last[P[k]] = k
                  # align end of pattern at index m-1 of text
              i = m-1                 # This is a pointer to T
              k = m-1                 # This is a pointer to P
              while i < n:            # Use the while loop to iterate over T
                  if T[i] == P[k]:    # If the match is successful and all matches
                      if k == 0:
                          return i
          

          串匹配算法綜述_串的模式匹配算法是指_串的模式匹配算法實驗報告

          else: # If the match is successful but no all matches i -= 1 # Pointer forward k -= 1 else: j = last.get(T[i], -1) # If the current character appears in the mode character,Return index ,else -1 i += m - min(k, j+1) # Returns the starting pointer position by adding up the number of matched characters k = m-1 # Restore k return -1

          這段代碼的一個核心在于以下三條:
          

          j = last.get(T[i], -1)
          i += m - min(k, j+1)
          k = m-1
          

          通過字典last.get返回值判斷是否匹配成功過,如果字符在P中出現過,則返回索引(即還有多少個字符沒有匹配,然后通過m減去得到已經匹配的數量,在累加到i上,即可使i指針回到最初的位置,正常向后推進),否則返回-1,而在第二行中,使用了min函數判斷k和j+1的大小(如果沒有匹配到,則j+1得到0,m-0就會使指針i直接向后推進m個位置,極大程度上減少了運行速度。如果匹配成功過,則也可以通過min函數判斷k和j+1的大小使得m-min(k, j+1)能取得最大值)。
          最后呢,將k還原為最開始的m-1.
          如果使用傳統的查找表,在最壞的情況下BM算法的運行時間是o(nm)
          測試一下

          print(find_boyer_moore("abedef", "ede"))

          運行結果:

          3.Knuth-Morris-Pratt算法

          KMP算法對于模式有一個確定的調整,如果發現一些匹配的字符但后來又發現不匹配,在模式下一次重新匹配時,我們忽略所有由成功的比較而獲得的信息。這樣避免了信息的浪費,并且它能達到的運行時間為

          , 這是漸近最優運行時間。即在最壞的情況下,任何模式匹配算法將會對文本的所有字符和模式的所有字符檢查至少一次。KMP算法的主要思想是預先計算模式部分之間的自重疊,從而當不匹配發生在一個位置時,我們在繼續搜尋之前就能立刻知道移動模式的最大數目。

          失敗函數

          為了實現KMP算法,我們需要預先計算失敗函數

          ,該函數用于表示匹配失敗時P對應的位移。具體地,失敗函數f(k)定義為P的最長前綴的長度,它是P[1:K+1]的后綴(這里沒有包含P[0],因為至少會移動一個單元)。如果在字符P[k+1]中找不到匹配,函數f(k)會告訴我們多少緊接著的字符可以用來重啟模式

          def compute_kmp_fail(P):
              """Utility that computes and returns KMP 'fail' list."""
              m = len(P)
              fail = [0] * m          # by default. presume overlap of 0 everywhere
              j = 1
              k = 0
          

          串的模式匹配算法實驗報告_串的模式匹配算法是指_串匹配算法綜述

          while j < m: # compute f(j) during this pass, if nonzero if P[j] == P[k]: # k + 1 characters match thus fat fail[j] = k + 1 j += 1 k += 1 elif k > 0: # k follows a matching prefix k = fail[k-1] else: # no match found starting at j j += 1 return fail

          這是一個失敗函數,通過雙指針來匹配最大的重復前綴,它將模式與KMP中的模式進行比較。每次有兩個匹配的字符,我們設置f(j0 = k + 1。因為在整個算法中已經有j > k,當使用它時,f(k - 1)總是被定義好的。

          def find_kmp(T, P):
              """Return the lowest index of T at which substring P begins (or else -1)"""
              n, m = len(T), len(P)           # Get length of T and P's
              if m == 0: return 0             # Return 0 if P's length is 0
              fail = compute_kmp_fail(P)      # Call the compute_kmp_fail function to get the return list
              j = 0
              k = 0
              while j < n:
                  if T[j] == P[k]:
                      if k == m - 1:          # Complete match
                          return j - m + 1    # Return the index of the first matched character
                      j += 1                  # Match successful but no all, pointer forward
                      k += 1
                  elif k > 0:                 # Match failure but succeeded
                      k = fail[k - 1]         # Prefix rebound
                  else:
                      j += 1
              return -1

          這是一個KMP算法的實現,其中 k = fail[k-1]實現了不完全匹配時觸發的前綴回跳,以此來減少匹配次數,實現算法優化。不太理解的可以打個斷點觀察一下k的變化。

          測試一下:

          print(find_kmp("ababababef", "ababef"))

          運行結果:


          主站蜘蛛池模板: 无码视频一区二区三区| 日韩在线不卡免费视频一区| 国产在线一区二区三区在线| 久久久国产精品亚洲一区| 国产午夜精品一区二区三区小说| 日本精品一区二区三区视频| 亚洲综合色一区二区三区| 亚洲av午夜福利精品一区人妖| 久久精品一区二区三区中文字幕| 日本精品一区二区三区在线视频一 | 美日韩一区二区三区| 亚洲国产视频一区| 一区二区中文字幕| 日韩一区二区久久久久久| 国内精品无码一区二区三区| 国产伦精品一区二区免费| 一区二区日韩国产精品| 波多野结衣电影区一区二区三区| 午夜爽爽性刺激一区二区视频| 无码一区二区波多野结衣播放搜索| 亚洲一区免费在线观看| 无码乱人伦一区二区亚洲一| 日本一区二区不卡视频| 国产精品日本一区二区不卡视频| 国产色情一区二区三区在线播放 | 国产无线乱码一区二三区| 成人日韩熟女高清视频一区| 中文字幕人妻无码一区二区三区| 成人无码一区二区三区| 国产成人无码AV一区二区 | 国产亚洲3p无码一区二区| 国产在线精品一区二区中文| 日韩一区二区久久久久久| 麻豆一区二区99久久久久| 日韩精品一区二区亚洲AV观看| 亚洲视频一区在线| 丝袜美腿一区二区三区| 日韩人妻无码免费视频一区二区三区| 国产精品久久久久一区二区| 国产人妖视频一区在线观看| 天堂不卡一区二区视频在线观看|