32.1 The naive string matching algorithm

m = T.length n = P.length

$O((n-m+1)m)$

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
void NAIVE_STRING_MATCHER(char* T, int m , char* P, int n )
{
    for (int s = 0; s <= n - m; s++)
    {
        bool matching = true; // strcmp
        for (int i = 0; i < m; i++)
        {
            if (T[i+s] != P[i])
            {
                matching = false;
            }
        }
        if (matching)
        {
            std::cout << "Pattern occurs with shift" << s <<'\n';
        }
    }
}

32.2 The Rabin Karp algorighm

Preprocessing time : $O(m)$

Matching time $O((n-m+1)m)$ 평균 O(m)

q = prime

$d = \Sigma ^{*}$

I'm setting d = 26 (only Letter case)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void RABIN_KARP_MATCHER(char T[], int n , char P[], int m, int d, int q)
{
    int h = MODULAR_EXPONENTIATION(d, n - 1, q);
    int p = 0;
    int t_0 = 0;
    for (int i = 0; i < n; i++) //전처리
    {
        p = (d * p + (P[i]-'A')) % q;
        t_0 = (d * t_0 + (T[i]-'A')) % q;
    }
    for (int s = 0; s <= m - n ; s++)
    {
        if (p == t_0)
        {
            bool matching = true; // strcmp
            for (int i = 0; i < n; i++)
            {
                if (T[i + s] != P[i])
                {
                    matching = false;
                    break;
                }
            }
            if (matching)
            {
                std::cout << "Pattern occurs with shift" << s << '\n';
            }
        }
        if (s < m - n)
        {
            t_0 = ((d * (t_0 - (T[s]-'A') * h) + (T[s + n]-'A')) % q + q)%q;//음수가 나올수있기때문에 음수처리를 한다.
        }
    }
}

32.3 String matching with finite automata

https://www.acmicpc.net/problem/1786

Preprocessing time : $O(m^{3} |\Sigma|) $ 뒤의 kmp를 응용해서 해당 복잡도를 $O(m|\Sigma|) $ 로 줄일 수 있다.

Matching time $O(n)$

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
void FINITE_AUTOMATON_MATCHER(char T[], int n , std::vector<std::vector<int>> equation, int m )
{
    int q = 0;
    for (int i = 0; i < n ; i++)
    {
        q = equation[q][T[i]-'A'];
        if (q == m)
        {
            std::cout << "Pattern occurs with shift" << i-m+1 << '\n';
        }
    }
}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
std::vector<std::vector<int>> COMPUTE_TRANSITION_FUNCTION(char P[],int sigma, int m)//
{
    std::vector<std::vector<int>> transition_function;
    transition_function.resize(m+1);
    for (int i = 0; i <= m; i++)
    {
        transition_function[i].resize(sigma,0);
    }
    for (int q = 0; q <= m; q++)
    {
        for (char a = 0; a < sigma; a++)
        {
            int k = (m+1< q+2  ? m + 1: q+2);
            bool matching = true;
            do
            {
                k--;
                matching = true;
                if (k == 0)
                {
                    break;
                }
                if (P[k-1] != a+'A') // 접미사 매칭
                {
                    continue;
                }
                for(int i = 0; i < k ; i++)
                {
                    if (k - 2 - i < 0 || q - i < 0)
                    {
                        matching = false;
                        break;
                    }
                    if (P[k - 1 - i] != P[q-i])
                    {
                        break;
                    }
                }
            } while (matching);
            transition_function[q][a] = k;
        }
    }
    return transition_function;
}

32.4 The Knuth-Morris-Pratt algorithm

https://www.acmicpc.net/problem/1786

Preprocessing time : $O(m)$

Matching time $O(n)$

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
void KMP_MATCHER(char T[], int n, char P[], int m)
{
    std::vector<int> pi = COMPUTE_PREFIX_FUNCTION(P, m);
    int q = -1;
    for (int i = 0; i < n; i++)
    {
        while (q >= 0 && P[q + 1] != T[i])
        {
            q = pi[q];
        }
        if (P[q + 1] == T[i])
        {
            q++;
        }
        if (q+1 == m)
        {
            std::cout << "Pattern occurs with shift" << i - m + 1 << '\n';
            q = pi[q];
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
std::vector<int> COMPUTE_PREFIX_FUNCTION(char P[], int m)
{
    std::vector<int> pi;
    pi.resize(m);
    pi[0] = -1;
    int k = -1; 
    for (int q = 1; q < m; q++)
    {
        while (k > 0 && P[k+1] != P[q])
        {
            k = pi[k];
        }
        if (P[k + 1] == P[q])
        {
            k++;
        }
        pi[q] = k;
    }
    return pi;
}