字串演算法
Acme Design is a full service design agency.
Index
KMP
給定一個原始字串 S,求出單字 W 在字串 S 中所有出現的位置
1≤ | W | ≤ | S | ≤ \(10^6\)
暴搜
O(| S | * | W |)
好像有一些重複或這不需要的比對,怎麼化簡?
ex:
字串1 = ababcababcabd
字串2 =abcabd
KMP
ababcababcabd
abcabd
abcabd
abcabd
abcabd
abcabd
abcabd
abcabd
abcabd
abcabd
我們記錄看看字串依從每一個字元開始的與字串二的共同前綴
pre[0] = 2
pre[5] = 2
pre[1] = 0
pre[2] = 5
pre[3] = 0
pre[4] = 0
KMP
匹配失敗時前面會有一段不用重新匹配
而我們會發現之需要從目前有匹配到的與字串二有著相同前綴的地方開始
ababcababcabd
abcabd
ababcababcabd
abcabd
ababcababcabd
abcabd
次長共同前綴後綴
最長共同前綴後綴會是字串本身
以abcabd為例
字串 次長共同前綴後綴
a 無
ab 無
abc 無
abca a
abcab ab
abcabd 無
Failure function
如果匹配失敗,就移到其次長相同前綴後綴的地方
if 比對成功
移到下一個次元
else if 比對失敗
移到目前已匹配的共同次長前綴後綴的位置 // ex: 現在匹配到abca ,那就會移到後面的a
else 成功匹配全部字串
移到此字串的共同前綴後綴的位置此實作中,我們將空集合的index設為-1
1的index設為0
Failure function
int failure[MXN]; //儲存以第i個為結尾的次長相同前綴後綴
void KMP(string s, string w)
{
// i 為字串 s 當前 index, j 為字串 w 以匹配到的 index
for(int i = 0,j = -1; i < s.size(); i++) // j=-1代表此時還沒匹配到
{
while(j>=0 && s[i] != w[j+1]) // 無法匹配
j = failure[j];
if (w[j+1] == s[i])
j++;
if (j+1 == w.size())
ans++, j= failure[j];
}
}Failure function
int failure[MXN]; //儲存以第i個為結尾的次長相同前綴後綴
void build_failure(string w)
{
for (int i=1, j=failure[0]=-1; i<w.size(); i++) // 注意這裡i是從1開始喔!(0的failure是-1)
{
while(j >= 0 && w[i] != w[j+1])
j = failure[j];
if (w[i] == w[j+1])
j++;
failure[i] = j;
}
}跟上面應該蠻像的,想成字串2在跟自己比對
Trie (字典樹)
Trie (字典樹)
struct Trie()
{
Trie *c[26];
int cnt;
Trie():cnt(0)
{
memset(c, 0, sizeof(c));
}
}void insert(char *s)
{
Trie *ptr = root;
while(*s)
{
if ( !ptr->c[ch(*s)])
ptr->c[ch(*s)] = new Trie();
ptr = ptr->c[ch(*s)];
s++;
}
ptr->cnt++;
}Edit distance
M
O
V
I
L
O
V
E
E
Minimal
By yujuan
Minimal
- 234