백준: Class 6 - 1786(KMP 알고리즘)

2 분 소요


</br> KMP 알고리즘을 정리해 보자
1786번 문제 내용 자체도 kmp 알고리즘을 설명하고 있다
</br>

찾는 문자열 내 반복 찾기

    int psz = p.size();
    vector<int> pi(psz, 0);
    int start = 1, matched = 0;
    while( start + matched < psz ){
        if( p[start + matched] == p[matched] ){
            matched++;
            pi[start + matched - 1] = matched;
        }
        else{
            if( matched == 0 ) start++;
            else{
                start += matched - pi[matched - 1];
                matched = pi[matched - 1];
            }
        }
    }

일단 가장 처음이 반복될 수는 없으니 인덱스는 1부터 시작한다.
만약 p[start + matched] == p[matched]라면, 현재 일치한다는 뜻이므로 matched를 ++하고, pi[start + matched - 1]]에 matched를 기록한다.
만약 다를 경우, matched가 0이면 시작 부분을 뒤로 한 칸 민다.
matched가 있는 경우, 시작 부분은 그 만큼 넘어간다.

        0123456
ex) p = ABCDABD
s m
2 0
3 0
4 0
4 1   < p[0] = A와 매치
4 2   < p[1] = B와 매치
6 0   < matched가 있었으므로 시작 부분을 그 뒤로 민다
7 0
pi: 0 0 0 0 1 2 0


</br>

문자열 찾기

    matched = 0;
    for(int i = 0; i < t.size(); i++){
        while( matched > 0 && t[i] != p[matched] ){
            matched = pi[matched - 1];
        }
        if( t[i] == p[matched] ){
            matched++;
            if( matched == psz ){
                ans.push_back(i - psz + 2);
                matched = pi[matched - 1];
            }
        }
    }

matched = pi[matched - 1];로 탐색할 인덱스를 정한다.
만약 현재 t[i]p[matched]와 같은 경우, matched++한다. 만약 이 맞은 개수가 p의 크기와 같다면 찾은 것이므로 답에 추가한다.

</br>

1786: 찾기

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

#include <bits/stdc++.h>
#define P pair<int, int>

using namespace std;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(NULL);

    string t, p;
    getline(cin, t);
    getline(cin, p);

    int psz = p.size();
    vector<int> pi(psz, 0);
    int start = 1, matched = 0;
    while( start + matched < psz ){
        if( p[start + matched] == p[matched] ){
            matched++;
            pi[start + matched - 1] = matched;
        }
        else{
            if( matched == 0 ) start++;
            else{
                start += matched - pi[matched - 1];
                matched = pi[matched - 1];
            }
        }
    }

    vector<int> ans;
    matched = 0;
    for(int i = 0; i < t.size(); i++){
        while( matched > 0 && t[i] != p[matched] ){
            matched = pi[matched - 1];
        }
        if( t[i] == p[matched] ){
            matched++;
            if( matched == psz ){
                ans.push_back(i - psz + 2);
                matched = pi[matched - 1];
            }
        }
    }

    cout << ans.size() << '\n';
    for(int i = 0; i < ans.size(); i++){
        cout << ans[i] << '\n';
    }

}

전체 코드는 위와 같다.
</br>


새로운 게 많다
</br>

댓글남기기