KMP
字首函式
設 \(S_i\) 為字串 \(S\) 的第 \(i\) 個位置。
我們設 \(\pi(i)\) 表示字串以 \(i\) 結尾的字首的最長公共前字尾的長度。
這裡的前字尾都指的是真字首、真字尾。
怎麼 \(O(n)\) 求出 \(\pi(i)\)。
性質:相鄰的 \(\pi\) 至多增加 1。
因此, 若 \(s[\pi(i)+1]=s[i+1]\) 時,\(\pi(i+1)=\pi(i)+1\)。
如果失配,我們要找到 \(i\) 字首的第二長的公共前字尾,然後再次比較。以此類推。
那麼
\[[s_1s_2s_3s_4]...[s_{i-3}s_{i-2}s_{i-1}s_{i}]s_{i+1}
\]
如果 \(\pi(i)=4\),即 \(s[1...4]=s[i-3...i]\)。
而第二長的公共前字尾長度 \(j\),假如 \(j=2\),那麼 \(s[1...2]=s[i-1...i]\)。
由於 \(s[1...4]=s[i-3...i]\),那麼 \(s[i-1...i]=s[3...4]\),所以 \(s[1...2]=s[3...4]\)。
所以第二長的公共前字尾長度是字首 \(\pi(i)\) 的最長公共前字尾長度,即 \(\pi(\pi(i))\)。
所以如果 \(\pi(i)+1\) 失配,那麼就找到 \(\pi(\pi(i))+1\),然後是 \(\pi(\pi(\pi(i)))+1\dots\)
到最後找到 \(1\),若不相等則 \(\pi(i+1)=0\)。
KMP 演算法
對於文字串 \(s\) 和模式串 \(t\) 匹配,可以求出字串 \(t+\#+s\) 的字首函式,其中 \(\#\) 是一個額外字元,然後就能知道 \(s\) 每個字首能否與 \(t\) 匹配。