字串演算法

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