본문 바로가기

Algorithm/BOJ

[BOJ 16570] 앞뒤가 맞는 수열

KMP 문제

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

 

KMP 실패 함수 응용 문제입니다.


[문제 풀이]

 

앞에서부터 수열을 잘라가면서 접두부와 접미부가 일치하는 최대 길이와 그 길이가 가능한 방법의 수를 구하는 문제입니다.

 

아주 간단하게 생각해보면 수열을 앞에서부터 하나씩 자르면서 자른 수열의 앞뒤가 같은지 비교하고, 앞뒤가 다르다면 제일 앞의 수를 또 자르고 비교(생략)하면 됩니다.

그러나 이렇게 푼다면 앞에서부터 잘린 수열의 개수 N개에 대해 수열의 앞뒤를 비교하게 되는데, 1 1 1 ... 1과 같이 수열의 모든 요소가 같다면 위의 생략 과정이 없어지기에 시간복잡도는 $O(N^2)$이 됩니다.

N이 1,000,000이니 당연히 시간 초과입니다.

 

접두, 접미에 관한 내용이 나오니 실패 함수로 접근하고 싶기는 한데, 이 문제는 여의치 않습니다.

앞의 문자열을 하나씩 잘라가면서 실패 함수를 계속 만들면 시간복잡도는 마찬가지로 O(N^2)입니다.

심지어 평균적인 상황에서는 아주 간단하게 생각한 위의 코드보다도 느릴 겁니다.

 

 

이 문제에서 주목해야 할 점이 있습니다.

수열을 무조건 앞에서부터 자르므로 수열을 잘라내면서 계속 접두부 접미부를 비교할 때마다 접미부는 그대로라는 점입니다.

만약 접두부가 그대로였다면 어땠을까요?

단순한 실패 함수 문제가 됩니다.

 

이 문제는 앞부분을 자른다는 조건으로 $O(N^2)$ 문제인 척 위장했지만 사실은 뒤에서부터 실패 함수를 만드는 문제입니다.

뒤에서부터 실패 함수를 만들면서 한 번도 실패 테이블에 값이 갱신이 안 됐다면 -1을 출력하고, 아니라면 실패 테이블의 최댓값과 그 최댓값이 몇 개가 있는지 출력하면 됩니다.

 


[소스 코드] / C++

 

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;
int arr[1000000];
int table[1000000];

pair<int, int> makeTable(int N) {
    int ans = 0, count = 0;

    int j = 0;
    for (int i = 1; i < N; i++) {
        while (j > 0 && arr[i] != arr[j]) {
            j = table[j - 1];
        }

        if (arr[i] == arr[j]) {
            table[i] = ++j;

            if (j >= ans) {
                if (j > ans) {
                    ans = j;
                    count = 0;
                }
                ++count;
            }
        }
    }

    return make_pair(ans, count);
}

int main(void) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    
    int N; cin >> N;
    for (int i = 0; i < N; i++) {
        cin >> arr[i];
    }

    reverse(arr, arr + N);

    pair<int, int> ans = makeTable(N);

    if (ans.first == 0) {
        cout << -1;
    } else {
        cout << ans.first << ' ' << ans.second;
    }
    
    return 0;
}

'Algorithm > BOJ' 카테고리의 다른 글

[BOJ 1867] 돌멩이 제거  (2) 2023.02.27
[BOJ 3295] 단방향 링크 네트워크  (0) 2023.02.22
[BOJ 1106] 호텔  (1) 2023.01.18
[백준 14750] Jerry and Tom  (0) 2021.03.29
[백준 20152] Game Addiction  (0) 2021.03.24