1. 程式人生 > >字串之KMP演算法

字串之KMP演算法

一、介紹

  KMP演算法全稱Knuth-Morris-Pratt演算法,是一種字串匹配演算法,常規字元匹配是每次移動一位,複雜度O(mn);而KMP演算法複雜度O(m+n)。

二、演算法原理

  KMP演算法利用的是目標字串(要匹配的字串,如下圖第二行)前後綴有相同的子字串和在匹配過程中前i-1個字元已經匹配過的規律。
匹配過程:
這裡寫圖片描述
部分匹配表:
這裡寫圖片描述
從第一張圖中我們看到當我們目標字串第一位與被匹配字串字元相等時,我們向後移動指標,逐個匹配後面字元是否相等。當匹配字元D時,被匹配字串為空字元,顯然不等。這時與常規方法將目標字串整體向後移動一位不同。KMP演算法根據部分匹配表,D前面字元為B,對於值為2,將字串移動4位(移動位數=已經匹配字元ABDCAB長度6-字元B在部分匹配表中對應值2=4

),這是目標字串前面的AB就移動到後面AB所在位置了。
這裡寫圖片描述
從上圖變化中,我們看到了我們利用ABDCAB有相同前後綴AB,在我們比較到字元D位置後,字串ABDCABD前面的字串ABDCAB已經比較過了,利用這個資訊,我們直接把字首移動到字尾位置,完成移動K位。

關於此處為什麼可以直接移動4位,我們已經匹配到第一張圖所在位置,此時D匹配不符合。常規情況下我們後移一位,但是我們要明白往下移動一位我們仍要匹配到AB,也就是說如果後移一位後我們目標字串從0位開始重新匹配,至少在相應位置上仍然需要AB。而KMP演算法利用我們已經知道子字串ABDCAB字尾有AB,而且我們已經匹配過了,知道接下來的AB在被匹配字串上的位置。也就是說在AB前面的B,D,C位已經顯然不可能匹配成功了。

三、部分匹配表

  字首:除最後一個字元,前面字元的組合
  字尾:除第一個字元,後面字元的組合  

  如上圖:目標字串ABDCABD
  字首有:[A] [AB] [ABD] [ABDC] [ABDCA] [ABDCAB]
  字尾有:[D] [BD] [ABD] [CABD] [DCABD] [BDCABD]

  由前後綴的關係,我們可以算出一張表:
  對於字串A:前後綴為空集,公共元素為0;
  對於字串AB:字首[A],字尾[B],公共元素為0;
  對於字串ABD:字首[A] [AB],字尾[BD] [D],公共元素為0;
  對於字串ABDC:字首[A] [AB] [ABD],字尾[BDC] [DC] [C],公共元素為0;
  對於字串ABDCA:字首[A] [AB] [ABD] [ABDC],字尾[BDCA] [DCA] [CA] [A],公共元素為1。長度為1;
  對於字串ABDCAB:字首[A] [AB] [ABD] [ABDC] [ABDCA],字尾[BDCAB] [DCAB] [CAB] [AB] [B],公共元素為1。長度為2;
  對於字串ABDCA:字首[A] [AB] [ABD] [ABDC] [ABDCA] [ABDCAB],字尾[D] [BD] [ABD] [CABD] [DCABD] [BDCABD],公共元素為1;長度為3;
  如下表:
  這裡寫圖片描述

這裡必須是字首和字尾相同。如果不是字首而是中間綴的話我們就不能判斷中間綴前面的字元能否跟被匹配字串匹配上。所以需要從頭開始,也就是從字首開始匹配。

四、例題