大概说一下我的理解吧:
kmp本质上就是一个state machine:你维护一个state来记录当前匹配的字符数,假设
这个state名为match。每读入一个新字符,match就会发生变化:match = transition(
match, str[i])。当match等于pattern的长度时或字符用完时,算法就结束了。可以把
这个算法想象成吃豆人,只吃不吐。
具体的实现我见过两种,一种是deterministic,可以真正做到只吃不吐;另一种是non
-deterministic,有时候得吐一个。一般大家说的都是第二种,其实第一种更好理解。
deterministic版本中,transition表是一个大小为mn的table,这里m为pattern的长度
,n为输入charset的大小(例如小写字母就是26)。叫deterministic的原因是它可以
真正做到match = transition(match, str[i]),所以可以一直前进。缺点是建表开销
大。这个版本在红书里有讲解。
non-deterministic版本就是平时大家说的建partial match table的版本了。这个版本
无法真正做到match = transition(match, str[i]),而是需要通过当前对比结果来做
出判断(比较str[i]和pattern[match])。如果匹配则match = match + 1,i也可以前
进;如果不匹配,就需要计算match = pmt[match],而已经用过的str[i]还得拿出来再
用,直至str[i]被匹配或match==0时才可以跳过。注意match = pmt[match]是只减不增
的,因为它的含义是获取在pattern[0, match]中最长的matching proper prefix and
suffix的长度。这个版本的优点是O(n)建表,在pattern重复率不高的情况下几乎可以
一直前进。缺点除了难理解几乎没有。
具体建表方式就不说了,那个配合图看很好理解。