[C++] ๋ฌธ์ž์—ด

2021. 12. 1. 17:50ยท๐Ÿ“ Computer Science/โœ Algorithm

๋ฌธ์ž์—ด

1. KMP ์•Œ๊ณ ๋ฆฌ์ฆ˜

๋ฌธ์ž์—ด ๊ฒ€์ƒ‰์„ ๋น ๋ฅด๊ฒŒ ๊ตฌํ•˜๊ธฐ ์œ„ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.

 

1) ๊ธฐ๋ณธ ์›๋ฆฌ

์ ‘๋‘์‚ฌ(prefix)์™€ ์ ‘๋ฏธ์‚ฌ(suffix)๋ฅผ ์ด์šฉํ•ด pi[i] ๋ฐฐ์—ด์„ ๊ตฌํ•œ ๋’ค ํ™œ์šฉํ•œ๋‹ค. pi[i] ๋ฐฐ์—ด์€ 0~i๊นŒ์ง€์˜ ๋ถ€๋ถ„ ๋ฌธ์ž์—ด์—์„œ prefix=suffix๊ฐ€ ๋  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„ ๋ฌธ์ž์—ด ์ค‘ ๊ฐ€์žฅ ๊ธด ๊ฒƒ์˜ ๊ธธ์ด์ด๋‹ค. ์ด๋•Œ, prefix๊ฐ€ 0~i๊นŒ์ง€์˜ ๋ถ€๋ถ„ ๋ฌธ์ž์—ด๊ณผ ๊ฐ™์œผ๋ฉด ์•ˆ ๋œ๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด ๋ฌธ์ž์—ด ABAABAB๋กœ pi[i] ๋ฐฐ์—ด์„ ๊ตฌํ•ด๋ณด์ž.

 

 i ๋ถ€๋ถ„ ๋ฌธ์ž์—ด (0~i)   pi[i]
 0 A  0
 1 AB   0
 2 ABA  1
 3 ABAA  1
 4 ABAAB  2
 5 ABAABA  3
 6 ABAABAB  2

 

๊ทธ๋ ‡๋‹ค๋ฉด ์ด pi[i] ๋ฐฐ์—ด์„ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•˜์—ฌ ๋ฌธ์ž์—ด ๊ฒ€์ƒ‰์„ ํšจ์œจ์ ์œผ๋กœ ํ•  ๊ฒƒ์ธ๊ฐ€?

 

๋ฌธ์ž์—ด ABCDABCDABEE์—์„œ ๋ฌธ์ž์—ด ABCDABE๋ฅผ ์ฐพ๋Š” ์ƒํ™ฉ์„ ๊ฐ€์ •ํ•ด๋ณด์ž. ์•„๋ž˜์™€ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ๋ฌธ์ž์—ด ๋งค์น˜์— ์‹คํŒจํ–ˆ์„ ๋•Œ, ๊ธฐ์กด ๋ฌธ์ž์—ด ๊ฒ€์ƒ‰์€ ์ธ๋ฑ์Šค 1๋กœ ์ด๋™ํ•ด ๊ฒ€์ƒ‰์„ ์ง„ํ–‰ํ•œ๋‹ค.

 

์ธ๋ฑ์Šค 0 1 2 3 4 5 6 7 8 9 10 11
ํ…์ŠคํŠธ A B C D A B C D A B E E
ํŒจํ„ด A B C D A B E          

 

๊ทธ๋Ÿฌ๋‚˜, pi[i] ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ํ˜„์žฌ ๋‘ ๋ฌธ์ž์—ด์ด ์ผ์น˜ํ•˜๋Š” ๋ถ€๋ถ„ ๋ฌธ์ž์—ด์€ ABCDAB(0~5)์ด๊ณ  pi[5]=2์ด๋ฏ€๋กœ ์ด๋ฏธ ๋ฌธ์ž์—ด AB๊ฐ€ ์ผ์น˜ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์–ด ์ธ๋ฑ์Šค 1์ด ์•„๋‹Œ ์ธ๋ฑ์Šค 4๋กœ ๋„˜์–ด๊ฐ€ ๊ฒ€์ƒ‰์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

2) ๋ฌธ์ œ

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

 

1786๋ฒˆ: ์ฐพ๊ธฐ

์ฒซ์งธ ์ค„์—, T ์ค‘๊ฐ„์— P๊ฐ€ ๋ช‡ ๋ฒˆ ๋‚˜ํƒ€๋‚˜๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์Œ์ด ์•„๋‹Œ ์ •์ˆ˜๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค. ๋‘˜์งธ ์ค„์—๋Š” P๊ฐ€ ๋‚˜ํƒ€๋‚˜๋Š” ์œ„์น˜๋ฅผ ์ฐจ๋ก€๋Œ€๋กœ ๊ณต๋ฐฑ์œผ๋กœ ๊ตฌ๋ถ„ํ•ด ์ถœ๋ ฅํ•œ๋‹ค. ์˜ˆ์ปจ๋Œ€, T์˜ i๏ฝži+m-1๋ฒˆ ๋ฌธ์ž์™€ P์˜ 1๏ฝžm

www.acmicpc.net

#include <iostream>
#include <vector>
#include <string>
using namespace std;

vector<int> kmp(string T, string P)
{
    vector<int> answer;
    int n = T.size(), m = P.size();

    // pi[i] ๋ฐฐ์—ด ๊ตฌํ˜„
    vector<int> pi(m, 0);
    for (int i = 1, j = 0; i < m; i++) {
        while (j > 0 && P[i] != P[j])
            j = pi[j - 1];
        if (P[i] == P[j])
            pi[i] = ++j;
    }

    // kmp ํ•จ์ˆ˜ ๊ตฌํ˜„
    for (int i = 0, j = 0; i < n; i++) {
        while (j > 0 && T[i] != P[j])
            j = pi[j - 1];
        if (T[i] == P[j]) {
            if (j == m - 1) {
                answer.push_back(i - m + 2);
                j = pi[j];
            }
            else {
                j++;
            }
        }
    }

    return answer;
}

int main()
{
    string T, P;
    getline(cin, T);
    getline(cin, P);

    vector<int> answer = kmp(T, P);
    cout << answer.size() << "\n";
    for (auto i : answer)
        cout << i << "\n";
}

 

2. ๋ผ๋นˆ ์นดํ”„ ์•Œ๊ณ ๋ฆฌ์ฆ˜(Rabin-Karp Algorithm)

๋ฌธ์ž์—ด ๊ฒ€์ƒ‰์„ ๋น ๋ฅด๊ฒŒ ๊ตฌํ•˜๊ธฐ ์œ„ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.

 

1) ๊ธฐ๋ณธ ์›๋ฆฌ

ํ•ด์‹ฑ์— ๊ธฐ๋ฐ˜ํ•œ๋‹ค. ๋ฌธ์ž์—ด ๋‚ด ๋ชจ๋“  ์œ„์น˜์—์„œ ๋น„๊ตํ•˜๋Š”๋ฐ, ๋จผ์ € ํ•ด๋‹น ์œ„์น˜์˜ ํ•ด์‹œ๊ฐ’์„ ๋น„๊ตํ•˜๊ณ  ๊ฐ™๋‹ค๋ฉด ๊ทธ์ œ์•ผ ๋‹จ์ˆœ ๋น„๊ต๋ฅผ ํ•œ๋‹ค. ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ์ž˜ ๊ตฌํ˜„ํ•ด์„œ ์ถฉ๋Œ์ด ์ ์€ ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ ๋‹ค๋ฉด ์œ ์šฉํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๋  ๊ฒƒ์ด๋‹ค.

 

๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ํ•ด์‹œ ํ•จ์ˆ˜๋Š” Rabin fingerprint๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋ฅผ ๊ฐ–๊ณ  ์žˆ๋‹ค.

  • T[i]: ํ•ด๋‹น ๋ฌธ์ž์˜ ์•„์Šคํ‚ค์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.
H(i) = T[i] *2^(M-1)+ T[i+1] * 2^(M-2)+ ... + T[i+M-2]*2^(1) + T[i+M-1]*2^(0)
H(i) = 2 * (H(i-1) - T[i - 1] * 2^(M-1)) + T[i+M-1] (์ ํ™”์‹)

 

2) ๋ฌธ์ œ

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

 

3033๋ฒˆ: ๊ฐ€์žฅ ๊ธด ๋ฌธ์ž์—ด

์ฒซ์งธ ์ค„์— L์ด ์ฃผ์–ด์ง„๋‹ค. (1 ≤ L ≤ 200,000) ๋‹ค์Œ ์ค„์—๋Š” ๊ธธ์ด๊ฐ€ L์ด๋ฉด์„œ ์•ŒํŒŒ๋ฒณ ์†Œ๋ฌธ์ž๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฌธ์ž์—ด์ด ์ฃผ์–ด์ง„๋‹ค.

www.acmicpc.net

#include <iostream>
#include <vector>
#include <string>
using namespace std;
const int HASH_SIZE = 100003;

int Mod(long long x)
{
    if (x >= 0)
        return x % HASH_SIZE;
    return ((-x / HASH_SIZE + 1) * HASH_SIZE + x) % HASH_SIZE;
}

int main()
{
    int L;
    string str;
    cin >> L >> str;

    int start = 0, end = L;
    while (start + 1 < end) {
        vector <int> hash[HASH_SIZE];
        int mid = (start + end) / 2, h = 0, po = 1;
        bool found = false;

        // ํ•ด์‹œ๊ฐ’(h) ๋งŒ๋“ค๊ธฐ
        for (int i = 0; i <= L - mid; i++) {
            if (i == 0) {
                for (int j = 0; j < mid; j++) {
                    h = Mod(h + 1LL * str[mid - j - 1] * po);
                    if (j < mid - 1)
                        po = Mod(po * 2);
                }
            }
            else
                h = Mod(2 * (h - 1LL * str[i - 1] * po) + str[i + mid - 1]);

            if (!hash[h].empty()) {
                // ํ•ด์‹œ ์ถฉ๋Œ์ผ ๋•Œ str์˜ [i, i+m-1]์™€ [p, p+mid-1]์˜ ๋ฌธ์ž์—ด์ด ๊ฐ™์€์ง€ ๋น„๊ต
                for (int p : hash[h]) {
                    for (int j = 0; j < mid; j++) {
                        if (str[i + j] != str[p + j])
                            break;
                        if (j == mid - 1)
                            found = true;
                    }
                }
            }

            if (!found)
                hash[h].push_back(i);
        }

        if (found)
            start = mid; // ์ฐพ์•˜์œผ๋ฉด ๋” ๋†’์€ ๊ธธ์ด ํƒ์ƒ‰
        else
            end = mid; // ์—†์œผ๋ฉด ๋” ๋‚ฎ์€ ๊ธธ์ด ํƒ์ƒ‰
    }

    cout << start;
}

 

3. ๋งจ๋ฒ„-๋งˆ์ด์–ด์Šค ์•Œ๊ณ ๋ฆฌ์ฆ˜

์ ‘๋ฏธ์‚ฌ ๋ฐฐ์—ด์„ ๋น ๋ฅด๊ฒŒ ๊ตฌํ•˜๊ธฐ ์œ„ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.

 

1) ๊ธฐ๋ณธ ์›๋ฆฌ

์ ‘๋ฏธ์‚ฌ ๋ฐฐ์—ด(Suffix Array)์€ ์–ด๋–ค ๋ฌธ์ž์—ด์˜ ๋ชจ๋“  ์ ‘๋ฏธ์‚ฌ๋ฅผ ์‚ฌ์ „ ์ˆœ์œผ๋กœ ์ •๋ ฌํ•ด ๋‘” ๋ฐฐ์—ด์ด๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด ๋ฌธ์ž์—ด banana๋กœ sa[i] ๋ฐฐ์—ด์„ ๊ตฌํ•ด๋ณด์ž. ์ ‘๋ฏธ์‚ฌ๋Š” a, na, ana, nana, anana, banana๊ฐ€ ์žˆ๊ณ , ๊ทธ๊ฒƒ๋“ค์„ ์‚ฌ์ „ ์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. ์ด๋•Œ, sa[i] ๋ฐฐ์—ด์—๋Š” ์ ‘๋ฏธ์‚ฌ ๋ฌธ์ž์—ด์„ ์ €์žฅํ•  ์ˆœ ์—†์œผ๋‹ˆ ํ•ด๋‹น ์ ‘๋ฏธ์‚ฌ์˜ ์ฒซ ๋ฒˆ์งธ ์ธ๋ฑ์Šค๋ฅผ ์ €์žฅํ•œ๋‹ค.

 

 i sa[i] S[sa[i]]
 0 5 a
 1 3 ana
 2 1 anana
 3 0 banana
 4 4 na
 5 2 nana

 

์—ฌ๊ธฐ์„œ ์ ‘๋ฏธ์‚ฌ ๋ฐฐ์—ด์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์—ฌ๋Ÿฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์žˆ์ง€๋งŒ, ๊ทธ์ค‘ ๋งจ๋ฒ„-๋งˆ์ด์–ด์Šค ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ™œ์šฉํ•  ๊ฒƒ์ด๋‹ค. ์›๋ฆฌ๋Š” ์ ‘๋ฏธ์‚ฌ๋ฅผ ์ฒซ ํ•œ ๊ธ€์ž, ์ฒซ ๋‘ ๊ธ€์ž, ์ฒซ ๋„ค ๊ธ€์ž, ์ฒซ ์—ฌ๋Ÿ ๊ธ€์ž... ์ฒซ d*2 ๊ธ€์ž ์”ฉ ๋น„๊ตํ•ด๊ฐ€๋ฉฐ ์ •๋ ฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

์ฒซ ํ•œ ๊ธ€์ž(d=0) ๊ธฐ์ค€์ผ ๋•Œ, ๊ทธ๋ฃน 3๊ฐœ๋กœ ๋‚˜๋‰˜๋ฉฐ ๊ทธ๋ฃน 1๊ณผ ๊ทธ๋ฃน 3์— ์ถ”๊ฐ€ ๊ณ„์‚ฐ์ด ํ•„์š”ํ•˜๋‹ค.

  • ๊ทธ๋ฃน 1: anana, ana, a
  • ๊ทธ๋ฃน 2: banana
  • ๊ทธ๋ฃน 3: nana, na

์ฒซ ๋‘ ๊ธ€์ž(d=1) ๊ธฐ์ค€์ผ ๋•Œ, ๊ทธ๋ฃน 4๊ฐœ๋กœ ๋‚˜๋‰˜๋ฉฐ ๊ทธ๋ฃน 2์™€ ๊ทธ๋ฃน 4์— ์ถ”๊ฐ€ ๊ณ„์‚ฐ์ด ํ•„์š”ํ•˜๋‹ค.

  • ๊ทธ๋ฃน 1: a
  • ๊ทธ๋ฃน 2: anana, ana
  • ๊ทธ๋ฃน 3: banana
  • ๊ทธ๋ฃน 4: nana, na

๋งˆ์ง€๋ง‰์œผ๋กœ ์ฒซ ๋„ค ๊ธ€์ž(d=2) ๊ธฐ์ค€์ผ ๋•Œ, ๋“œ๋””์–ด ๋ชจ๋“  ์ ‘๋ฏธ์‚ฌ๊ฐ€ ๊ฐ๊ฐ์˜ ๊ทธ๋ฃน์œผ๋กœ ๋‚˜๋‰˜์—ˆ๋‹ค. (๊ทธ๋ฃน์ˆ˜ = ์ ‘๋ฏธ์‚ฌ์ˆ˜)

  • ๊ทธ๋ฃน 1: a
  • ๊ทธ๋ฃน 2: ana
  • ๊ทธ๋ฃน 3: anana
  • ๊ทธ๋ฃน 4: banana
  • ๊ทธ๋ฃน 5: na
  • ๊ทธ๋ฃน 6: nana

 

ํ•œ ๋ฒˆ ๋‹ค๋ฅธ ๊ทธ๋ฃน์— ์†ํ•œ ์ ‘๋ฏธ์‚ฌ๋“ค์€ ๋‹ค์‹œ ๊ฐ™์€ ๊ทธ๋ฃน์— ์†ํ•  ์ˆ˜ ์—†๊ณ  ๊ฐ™์€ ๊ทธ๋ฃน์— ์†ํ•˜๋ ค๋ฉด ์ฒซ d*2 ๊ธ€์ž๊ฐ€ ๊ฐ™์•„์•ผ ํ•œ๋‹ค.

 

์ฒซ ํ•œ ๊ธ€์ž(d=0) ๊ธฐ์ค€์ผ ๋•Œ๋กœ ์‹œ์ž‘ํ•ด ์ฒ˜์Œ ๊ทธ๋ฃน์„ ๋‚˜๋ˆˆ ํ›„ ๊ทธ๋‹ค์Œ ๋ฃจํ”„๋ถ€ํ„ฐ๋Š” ๊ฐ ์ ‘๋ฏธ์‚ฌ๊ฐ€ ์ด์ „ ๋ฃจํ”„์—์„œ ๋ช‡ ๋ฒˆ์งธ ๊ทธ๋ฃน์— ์†ํ–ˆ๋Š”์ง€ ์•ˆ๋‹ค๋ฉด 1์ฐจ์ ์ธ ๋น„๊ต๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

  • ๋‘ ์ ‘๋ฏธ์‚ฌ๊ฐ€ ์ด์ „ ๋ฃจํ”„์—์„œ ๊ทธ๋ฃน ๋ฒˆํ˜ธ๊ฐ€ ๋‹ค๋ฅด๋‹ค๋ฉด, ๊ทธ๋ฃน ๋ฒˆํ˜ธ๊ฐ€ ํด์ˆ˜๋ก ์‚ฌ์ „ ์ˆœ์œผ๋กœ ๋’ค์— ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.
  • ๋‘ ์ ‘๋ฏธ์‚ฌ๊ฐ€ ์ด์ „ ๋ฃจํ”„์—์„œ ๊ทธ๋ฃน ๋ฒˆํ˜ธ๊ฐ€ ๊ฐ™๋‹ค๋ฉด, ๊ทธ์ œ์•ผ d*2 ๊ธ€์ž๋ถ€ํ„ฐ ๋น„๊ตํ•œ๋‹ค. ์ด๋•Œ, d*2 ๊ธ€์ž๋ถ€ํ„ฐ ๋๊นŒ์ง€๋„ ๋ฌธ์ž์—ด์˜ ์ ‘๋ฏธ์‚ฌ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋˜๋ฏ€๋กœ ๋‹ค์‹œ ๊ทธ๋ฃน ๋ฒˆํ˜ธ๋กœ ๋น„๊ตํ•œ๋‹ค.

 

2) ๋ฌธ์ œ

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

 

9248๋ฒˆ: Suffix Array

Suffix Array๋ž€, ๋ฌธ์ž์—ด S๊ฐ€ ์žˆ์„ ๋•Œ ๊ทธ ์ ‘๋ฏธ์‚ฌ๋“ค์„ ์ •๋ ฌํ•ด ๋†“์€ ๋ฐฐ์—ด์ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฌธ์ž์—ด S=banana์˜ ์ ‘๋ฏธ์‚ฌ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์ด 6๊ฐœ๊ฐ€ ์žˆ๋‹ค. Suffix i banana 1 anana 2 nana 3 ana 4 na 5 a 6 ์ด๋ฅผ Suffix ์ˆœ์œผ๋กœ ์ •

www.acmicpc.net

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int sa[500000], lcp[500000];
int g[500000], tg[500000];

string s;
int n, t;

bool compare(int a, int b)
{
	if (g[a] == g[b])
		return g[a + t] < g[b + t];
	return g[a] < g[b];
}

void SuffixArray()
{
	t = 1, g[n] = -1;
	for (int i = 0; i < n; i++) {
		sa[i] = i;
		g[i] = s[i] - 'a'; // ์ฒซ ๋ฒˆ์งธ ๋ฃจํ”„๋Š” ์ œ์ž๋ฆฌ ๋ฌธ์ž๋กœ ๋น„๊ต
	}

	while (t <= n) {
		sort(sa, sa + n, compare);

		// ์•ž์—์„œ๋ถ€ํ„ฐ ๊ฐ ์ ‘๋ฏธ์‚ฌ๊ฐ€ ๋‹ค๋ฅธ ๊ทธ๋ฃน์— ์†ํ•  ๋•Œ๋งˆ๋‹ค ๊ทธ๋ฃน ๋ฒˆํ˜ธ๋ฅผ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค.
		for (int i = 1; i < n; i++)
			tg[sa[i]] = tg[sa[i - 1]] + (compare(sa[i - 1], sa[i]) ? 1 : 0);

		t *= 2;
		for (int i = 0; i < n; i++)
			g[i] = tg[i];
	}
}

void LCP()
{
	int tmp[500000]{};
	for (int i = 0; i < n; i++)
		tmp[sa[i]] = i;

	int len = 0;
	for (int i = 0; i < n; i++) {
		if (tmp[i]) {
			int j = sa[tmp[i] - 1];
			while (s[j + len] == s[i + len])
				len++;

			lcp[tmp[i]] = len;

			if (len)
				len--;
		}
	}
}

int main()
{
	cin >> s;

	n = s.length();
	SuffixArray();
	LCP();

	for (int i = 0; i < n; i++)
		cout << sa[i] + 1 << " ";
	cout << "\nx ";
	for (int i = 1; i < n; i++)
		cout << lcp[i] << " ";
}

 

4. ์•„ํ˜ธ ์ฝ”๋ผ์‹ ์•Œ๊ณ ๋ฆฌ์ฆ˜(Aho-Corasick Algorithm)

  • ์ผ๋Œ€๋‹ค ํŒจํ„ด ๋งค์นญ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ๋ฌธ์ž์—ด ํ•˜๋‚˜ ์•ˆ์— ์—ฌ๋Ÿฌ ๊ฐ๊ฐ์˜ ๋ฌธ์ž์—ด์ด ์กด์žฌํ•˜๋Š”์ง€๋ฅผ ํŒ๋ณ„ํ•œ๋‹ค.
  • KMP ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ํ™•์žฅ์ด๋‹ค.

 

1) ๊ธฐ๋ณธ ์›๋ฆฌ

๊ทธ๋ฆผ์„ ๋ณด๋ฉด ์•Œ๊ฒ ์ง€๋งŒ, ์ผ์ข…์˜ ํŠธ๋ผ์ด์ด๋‹ค.

 

์•„ํ˜ธ ์ฝ”๋ผ์‹ ์•Œ๊ณ ๋ฆฌ์ฆ˜

 

  • ๋ฌธ์ž์—ด S ๋‚ด ๋ฌธ์ž c๋ฅผ ํ•˜๋‚˜์”ฉ ์ฝ์–ด๊ฐ€๋ฉฐ ์ง„ํ–‰ํ•˜๋Š”๋ฐ, ์‹œ์ž‘ state๋Š” ์ œ์ผ ์™ผ์ชฝ ๋…ธ๋“œ์ด๋‹ค.
  • ๋‹ค์Œ state๋Š” go ํ•จ์ˆ˜๋กœ ์ •์˜ํ•˜๋ฉฐ ์ด ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ด๋™ํ•œ๋‹ค.
  • output ๋…ธ๋“œ(๋นจ๊ฐ„ ๋…ธ๋“œ)์— ๋„์ฐฉํ–ˆ๋‹ค๋ฉด, ๋…ธ๋“œ์— ์ ํ˜€์žˆ๋Š” ๋ฌธ์ž์—ด์ด ๋ฌธ์ž์—ด S์— ๋“ฑ์žฅํ•œ๋‹ค๋Š” ๋œป์ด๋‹ค.
  • ๋งŒ์•ฝ ๊ฐˆ ๊ณณ์ด ์—†์–ด์ง€๋ฉด, ๋‹จ์ˆœํžˆ ์‹œ์ž‘ ์ง€์ ์ด ์•„๋‹ˆ๋ผ fail ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋‹ค๋ฅธ ์–ด๋–ค ๊ณณ์œผ๋กœ ๋ณด๋‚ธ๋‹ค.

 

์ •๋ฆฌํ•˜์ž๋ฉด ๋‹ค์Œ state๋กœ ์ด๋™ํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

1. ํ˜„์žฌ state x, ์ธํ’‹ c์— ๋Œ€ํ•ด go(x, c)๊ฐ€ ์žˆ์œผ๋ฉด ํ•ด๋‹น ๋…ธ๋“œ๋กœ ์ด๋™ํ•œ๋‹ค.

2. ๋งŒ์•ฝ ์—†๋‹ค๋ฉด, fail(x)๋กœ ์ด๋™ํ•œ ํ›„ 1๋กœ ๋Œ์•„๊ฐ„๋‹ค. ๋‹จ, ์ด๋ฏธ ๋ฃจํŠธ๋ฉด ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

์—ฌ๊ธฐ์„œ fail ํ•จ์ˆ˜๋ฅผ ์–ผ๋งˆ๋‚˜ ํšจ์œจ์ ์ด๊ฒŒ ๊ตฌํ˜„ํ•˜๋А๋ƒ๊ฐ€ ํฌ์ธํŠธ์ด๋‹ค.

  • fail ํ•จ์ˆ˜๋Š” ๋ฐ˜๋“œ์‹œ ์ž์‹ ๋ณด๋‹ค ๊นŠ์ด๊ฐ€ ์ž‘์€ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค. (๋ฃจํ”„ ๋…ธ๋“œ ์ œ์™ธ)
  • fail(x)=y์ด๋ฉด, y๋Š” x์˜ ์ ‘๋ฏธ์‚ฌ ์ค‘ ๊ฐ€์žฅ ๊ธด ์ ‘๋ฏธ์‚ฌ์ด๋‹ค. (x ์ž์‹  ์ œ์™ธ)

 

2) ๋ฌธ์ œ

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

 

9250๋ฒˆ: ๋ฌธ์ž์—ด ์ง‘ํ•ฉ ํŒ๋ณ„

์ง‘ํ•ฉ S๋Š” ํฌ๊ธฐ๊ฐ€ N์ด๊ณ , ์›์†Œ๊ฐ€ ๋ฌธ์ž์—ด์ธ ์ง‘ํ•ฉ์ด๋‹ค. Q๊ฐœ์˜ ๋ฌธ์ž์—ด์ด ์ฃผ์–ด์กŒ์„ ๋•Œ, ๊ฐ ๋ฌธ์ž์—ด์˜ ๋ถ€๋ถ„ ๋ฌธ์ž์—ด์ด ์ง‘ํ•ฉ S์— ์žˆ๋Š”์ง€ ํŒ๋ณ„ํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ์ž‘์„ฑํ•˜์‹œ์˜ค. ๋ฌธ์ž์—ด์˜ ์—ฌ๋Ÿฌ ๋ถ€๋ถ„ ๋ฌธ์ž์—ด ์ค‘ ํ•˜

www.acmicpc.net

#include <iostream>
#include <queue>
#include <string>
#include <algorithm>
using namespace std;

struct Trie {    
    Trie* go[26]; // ํ˜„์žฌ ๋…ธ๋“œ์—์„œ ํ•ด๋‹น ๋ฌธ์ž๋ฅผ ๋ฐ›์œผ๋ฉด ๊ฐ€๋Š” ๋…ธ๋“œ    
    Trie* fail; // ํ˜„์žฌ ๋…ธ๋“œ์—์„œ ํ•ด๋‹น ๋ฌธ์ž์˜ go ๋ชฉ์ ์ง€๊ฐ€ ์—†์„ ๋•Œ ๊ฐ€๋Š” ๋…ธ๋“œ
    bool output; // ํ˜„์žฌ ๋…ธ๋“œ์— ๋„๋‹ฌํ•˜๋ฉด ์ฐพ๋Š” ๋ฌธ์ž์—ด ์ง‘ํ•ฉ ์žˆ๋Š”์ง€ ํŒ๋‹จ

    Trie() 
    {
        fill(go, go + 26, nullptr);
        output = false;
    }

    ~Trie() 
    {
        for (int i = 0; i < 26; i++)
            if (go[i])
                delete go[i];
    }

    void insert(string key)
    {
        if (key == "\0") {
            output = true;
            return;
        }

        int next = key[0] - 'a';
        if (!go[next])
            go[next] = new Trie;

        // ๋งจ ์•ž ๋ฌธ์ž๋Š” ์ œ์™ธํ•˜๊ณ  ์ „๋‹ฌํ•œ๋‹ค.
        go[next]->insert(key.substr(1, key.size() - 1));
    }
};

int main()
{
    int N, M;
    string str;
    Trie* root = new Trie;

    cin >> N;
    for (int i = 0; i < N; i++) {
        cin >> str;
        // ํŠธ๋ผ์ด์— S์˜ ์›์†Œ๋“ค์„ ๋ชจ๋‘ ์ง‘์–ด๋„ฃ๋Š”๋‹ค.
        root->insert(str);
    }

    // ํŠธ๋ผ์ด ๋…ธ๋“œ๋ฅผ ๋ฐฉ๋ฌธํ•˜๋ฉฐ fail ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ ๋‹ค.
    queue<Trie*> q;
    root->fail = root;
    q.push(root);
    while (!q.empty()) {
        Trie* current = q.front();
        q.pop();

        // 26๊ฐœ์˜ input ๊ฐ๊ฐ์— ๋Œ€ํ•ด ์ฒ˜๋ฆฌํ•œ๋‹ค.
        for (int i = 0; i < 26; i++) {
            Trie* next = current->go[i];
            if (!next)
                continue;

            // ๋ฃจํŠธ์˜ fail์€ ๋ฃจํŠธ๋‹ค.
            if (current == root)
                next->fail = root;
            else {
                Trie* dest = current->fail;

                // fail์„ ์ฐธ์กฐํ•  ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์กฐ์ƒ์„ ์ฐพ์•„๊ฐ„๋‹ค.
                while (dest != root && !dest->go[i])
                    dest = dest->fail;

                // fail(px) = go(fail(p), x)
                if (dest->go[i])
                    dest = dest->go[i];

                next->fail = dest;
            }

            // fail(x) = y์ผ ๋•Œ, output(y) ⊂ output(x)
            if (next->fail->output)
                next->output = true;

            // ํ์— ๋‹ค์Œ ๋…ธ๋“œ push
            q.push(next);
        }
    }

    cin >> M;
    for (int i = 0; i < M; i++) {
        cin >> str;

        Trie* current = root;
        bool result = false;
        for (int j = 0; str[j]; j++) {
            int next = str[j] - 'a';

            // ํ˜„์žฌ ๋…ธ๋“œ์—์„œ ๊ฐˆ ์ˆ˜ ์—†์œผ๋ฉด fail์„ ๊ณ„์† ๋”ฐ๋ผ๊ฐ
            while (current != root && !current->go[next])
                current = current->fail;

            // go ํ•จ์ˆ˜๊ฐ€ ์กด์žฌํ•˜๋ฉด ์ด๋™. ๋ฃจํŠธ๋ฉด ์ด๊ฒŒ false์ผ ์ˆ˜๋„ ์žˆ๋‹ค
            if (current->go[next])
                current = current->go[next];

            // ํ˜„์žฌ ๋…ธ๋“œ์— output์ด ์žˆ์œผ๋ฉด ์ฐพ์€ ๊ฒƒ์ด๋‹ค.
            if (current->output) {
                result = true;
                break;
            }
        }

        cout << (result ? "YES" : "NO") << endl;
    }
}

 

์ฐธ๊ณ 

https://bowbowbow.tistory.com/6

 

KMP : ๋ฌธ์ž์—ด ๊ฒ€์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜

๋ฌธ์ž์—ด ๊ฒ€์ƒ‰์ด ๋ญ์ง€? ์›Œ๋“œํ”„๋กœ์„ธ์„œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ฐพ๊ธฐ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•œ์  ์žˆ์„ ๊ฒ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €์—์„œ๋„ Ctrl+F ๋‹จ์ถ•ํ‚ค๋ฅผ ๋ˆŒ๋Ÿฌ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ์ด๋ฏธ์ง€๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ "ํ…Œ์ดํ”„"๋ฅผ ๊ฒ€์ƒ‰ํ–ˆ์„

bowbowbow.tistory.com

 

์ €์ž‘์žํ‘œ์‹œ (์ƒˆ์ฐฝ์—ด๋ฆผ)
'๐Ÿ“ Computer Science/โœ Algorithm' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • [C++] ๋ˆ„์  ํ•ฉ(Prefix sum)
  • [C++] ์ค‘๊ฐ„์—์„œ ๋งŒ๋‚˜๊ธฐ(Meet In The Middle)
  • [C++] ๋„คํŠธ์›Œํฌ ์œ ๋Ÿ‰(Network Flow)
  • [C++] ํฌ์†Œ ํ…Œ์ด๋ธ”(Sparse Table)
Blxxming
Blxxming
CS ์ง€์‹๊ณผ ๊ณต๋ถ€ํ•˜๋‹ค ๋ฐฐ์šด ๊ฒƒ, ๊ฒฝํ—˜ํ•œ ๊ฒƒ ๋“ฑ์„ ๊ธฐ๋กํ•˜๋Š” ๋ธ”๋กœ๊ทธ์ž…๋‹ˆ๋‹ค.
  • Blxxming
    ๐Ÿ’ก๋ฒˆ๋œฉ๐Ÿ’ก
    Blxxming
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
  • ๊ณต์ง€์‚ฌํ•ญ

    • Tech Interview
    • ๐Ÿ“š Tech (246)
      • ๐Ÿ“ Computer Science (96)
        • โœ OS (12)
        • โœ Network & Web (10)
        • โœ Database (11)
        • โœ Data Structure (6)
        • โœ Algorithm (40)
        • โœ Design Pattern (9)
        • โœ Cloud Computing (3)
        • โœ (5)
      • ๐Ÿ“ Language (73)
        • โœ Language (6)
        • โœ C & C++ (11)
        • โœ C# (19)
        • โœ JAVA (37)
      • ๐Ÿ“ Game (43)
        • โœ Computer Graphics (2)
        • โœ Unity (14)
        • โœ Unreal (26)
        • โœ (1)
      • ๐Ÿ“ Book (34)
        • โœ Effective (3)
        • โœ Game Server (16)
        • โœ Clean Code (14)
        • โœ (1)
  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.0
Blxxming
[C++] ๋ฌธ์ž์—ด
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”