前言
經常會遇到一類需求,在一段字串中查詢所有能匹配上的模式,比如查詢一段文字匹配上字典中哪些短語。這時為了高效處理,就會考慮 AC 自動機,即 Aho-Corasick 自動機演算法。它的核心思想是通過有限自動機巧妙地將字元比較轉化為了狀態轉移。
通過 AC 自動機能做到匹配時不需要回溯,而且時間複雜度為 O(n),即時間複雜度與詞典的規模無關。
暴力匹配
暴力匹配就是一個一個比較,將模式串從頭到尾匹配主串字串,如下圖模式串"ABCE"比較主串,一旦遇到不相同的則往後移以為,重新開始比較,直到比對完主串,接著第二個模式串繼續比較。該方法簡單暴力,很好理解,但時間複雜度高,O(mn)。
AC自動機
AC自動機主要是將 n 個模式串構建成一個確定性的樹形有限狀態機,然後將主串作為該有限狀態機的輸入,使該狀態機進行狀態的轉換,當到達某些特定的狀態時則說明發生模式匹配。
通過例子來理解,以 he、she、his、hers
為模式串,ushers
為主串,構成了如下的狀態機。
在狀態機內部,可以看到有實線和虛線箭頭,優先以實線標明方向轉換狀態,當無法實線轉換時才使用虛線轉換。
另外,當轉換到圖中紅圈位置時說明發生了模式匹配,比如對於he
,從根節點到1再到2,此時符合he
,說明發生了模式匹配。
根據上圖你可以試試看ushers
會匹配出哪些模式,並且比劃下狀態的轉換過程。
AC的三個函式
AC自動機包含了三個核心函式,基本上理解了他們就搞懂AC了。
- goto函式,用來指導狀態轉換,即在當前狀態下,輸入一個字元後該轉到哪個狀態,對應的是上圖中的實線部分。
- failure函式,用來指導匹配失敗時的狀態轉換,即在當前狀態下,輸入一個字元後沒辦法根據實線進行轉換了,此時根據虛線進行轉換,對應上圖虛線部分。
- output函式,描述哪些狀態下發生了匹配,匹配的模式是什麼。
實現
實現AC自動機時一般都會用TRIE樹結構,那麼就會定義一個ACTrieNode
類,包含了子節點、值、output、failure節點等等屬性。
public class ACTrieNode {
private ACTrieNode[] children;
private byte[] value;
private boolean deleted = false;
private int status;
private ACArray[] results = null;
private ACTrieNode failureNode;
private static String encoding = "utf-8";
}
複製程式碼
詳細實現看github,https://github.com/sea-boat/TextAnalyzer/blob/master/src/main/java/com/seaboat/text/analyzer/segment/ACTrieTree.java。
-------------推薦閱讀------------
跟我交流,向我提問:
公眾號的選單已分為“讀書總結”、“分散式”、“機器學習”、“深度學習”、“NLP”、“Java深度”、“Java併發核心”、“JDK原始碼”、“Tomcat核心”等,可能有一款適合你的胃口。
歡迎關注: