긴 텍스트 \(T\) 안에서 단어(패턴) \(W\)가 몇 번 등장하는지(겹침 허용) 세는 전형적인 문자열 매칭 문제다.
\(|T|\)가 최대 \(1{,}000{,}000\)까지 커질 수 있으므로, \(O(|W|\cdot|T|)\) 같은 단순 비교는 시간 초과가 나기 쉽고 KMP로 \(O(|W|+|T|)\)에 해결한다.
문제 정보
문제 링크: https://www.acmicpc.net/problem/9120
문제 요약:
- 테스트케이스마다 패턴 문자열 \(W\)와 텍스트 문자열 \(T\)가 주어진다.
- \(T\)에서 \(W\)가 등장하는 횟수를 출력한다.
- 등장 위치는 겹쳐도 된다. (예: \(W=\) “AA”, \(T=\) “AAAA” 이면 3번)
제한 조건:
- 시간 제한: 1초
- 메모리 제한: 128MB
- \(1 \le |W| \le 10{,}000\)
- \(|W| \le |T| \le 1{,}000{,}000\)
- 알파벳: ‘A’..‘Z’
입출력 예제
입력 1:
| |
출력 1:
| |
접근 방식
핵심 관찰: KMP는 “현재까지 맞춘 접두사 길이”를 유지하며 한 번만 스캔한다
KMP는 패턴 \(W\)에 대해 접두사 함수(= 실패 함수) \(\pi\)를 만든다.
- \(\pi[i]\): \(W[0..i]\)의 접두사이면서 접미사인 것들 중 가장 긴 길이
텍스트 \(T\)를 왼쪽부터 훑으면서, 현재 일치한 길이 \(j\)를 유지한다.
- \(T[i]\)와 \(W[j]\)가 다르면, \(j=\pi[j-1]\)로 줄여서 “가능한 다음 후보”로 이동
- 끝까지 매칭(\(j = |W|-1\))되면 정답을 1 증가시키고, 겹침 허용을 위해 \(j=\pi[j]\)로 되돌린다
알고리즘 설계 (Mermaid Flowchart)
flowchart TD
A["입력: 테스트케이스 수"] --> B["각 케이스마다 W, T 입력"]
B --> C["pi = prefix_function(W)"]
C --> D["i = 0, j = 0, cnt = 0"]
D --> E{"i < |T| ?"}
E -- "yes" --> F{"T[i] == W[j] ?"}
F -- "no" --> G{"j > 0 ?"}
G -- "yes" --> H["j = pi[j-1]"]
G -- "no" --> I["i = i + 1"]
H --> F
F -- "yes" --> J{"j == |W|-1 ?"}
J -- "no" --> K["i = i + 1j = j + 1"]
J -- "yes" --> L["cnt = cnt + 1i = i + 1j = pi[j] (겹침 허용)"]
K --> E
L --> E
E -- "no" --> M["cnt 출력"]
구현 포인트
- 겹침 처리: 매칭이 끝났을 때 \(j\)를 0으로 만들면 겹치는 매칭을 놓칠 수 있다. 반드시
j = pi[j](또는pi[m-1])로 이동한다. - 입력 크기: \(T\)가 최대 \(10^6\)이므로
cin은sync_with_stdio(false)와tie(nullptr)를 켜고 사용한다. - 정답 타입: 한 케이스에서 최대 \(10^6\)번까지 나올 수 있으므로
long long로 안전하게 출력한다.
복잡도 분석
| 항목 | 복잡도 | 비고 |
|---|---|---|
| 시간 복잡도 | (O( | W |
| 공간 복잡도 | (O( | W |
코너 케이스 및 실수 포인트
| 케이스 | 설명 | 처리 방법 |
|---|---|---|
| 겹치는 매칭 | 예: \(W=\) “AAA”, \(T=\) “AAAAA” | 매칭 후 j = pi[j]로 이동 |
| 패턴 길이 1 | \(W=\) “A” | 일반 로직 그대로 동작 |
| 반복 문자 텍스트 | \(T=\) “TTTT…T” | KMP는 선형 시간 유지 |
| 매칭 없음 | 결과 0 | 카운트 증가 조건 확인 |
| 여러 테스트케이스 | 입력이 큼 | 빠른 I/O 사용 |
구현 코드 (C++)
| |
![Featured image of post [Algorithm] C++ 백준 9120번: Oulipo 다국어](/post/algorithm/2026-01-05-boj-9120-oulipo-multilingual-kmp-string-matching-cpp-solution/wordcloud_hu_6b77f25cd62b9dff.png)
![[Algorithm] C++ 백준 18874번: Haircut](/post/algorithm/2026-01-05-boj-18874-haircut-fenwick-tree-inversion-cpp-solution/wordcloud_hu_f1156fbd3412a468.png)
![[Algorithm] C++ 백준 9120번: Oulipo 다국어](/post/algorithm/2026-01-05-boj-9120-oulipo-multilingual-kmp-string-matching-cpp-solution/wordcloud_hu_cabf7853c1ed85cc.png)
![[Algorithm] C++ 백준 14289번: 본대 산책 3](/post/algorithm/2026-01-02-boj-14289-bondae-walk-3-matrix-exponentiation-cpp-solution/wordcloud_hu_ae0f59803f116fbf.png)
![[Algorithm] C++ 백준 12012번: Closing the Farm (Gold)](/post/algorithm/2025-12-23-boj-12012-closing-the-farm-dsu-offline-cpp-solution/wordcloud_hu_5a95d85e90d9352c.png)
![[Algorithm] C++ 백준 1258번: 문제 할당](/post/algorithm/2025-12-23-boj-1258-problem-assignment-hungarian-cpp-solution/wordcloud_hu_fb5f370a4bccc9ee.png)
![[Algorithm] C++ 백준 7727번: Byephone](/post/algorithm/2025-12-19-boj-7727-byephone-hirschberg-lcs-cpp-solution/wordcloud_hu_7264c733e5d43dbc.png)
![[Algorithm] C++ 백준 4354번: 문자열 제곱](/post/algorithm/2025-12-02-boj-4354-string-power-period-kmp-cpp-solution/wordcloud_hu_cd8c6924b1ac5ab.png)
![[Algorithm] C++ 백준 9250번: 문자열 집합 판별](/post/algorithm/2025-08-14-boj-9250-string-set-membership-aho-corasick-cpp-solution/wordcloud_hu_18eda8d77d438bc5.png)
![[Algorithm] C++ 백준 25201번: 보드 뒤집기 게임](/post/algorithm/2025-12-19-boj-25201-board-flipping-game-cpp-solution/wordcloud_hu_22b1d8c414e9b6d9.png)
![[Algorithm] C++ 백준 13576번: Prefix와 Suffix](/post/algorithm/2025-08-14-boj-13576-prefix-and-suffix-cpp-solution/wordcloud_hu_72d54380bd8dc598.png)