읽는데 약 2분
[백준 20191] 줄임말
문제
https://www.acmicpc.net/problem/20191
알고리즘
이분탐색
풀이
문자열 S와 T가 주어집니다. Tn을 문자열 T를 n회 반복한 문자열이라고 정의할 때, n번 반복하여 줄임말 S를 만들기 위한 최소 n을 구하는 문제입니다.
줄임말을 만들 때, 순서를 유지한다는 점에서 투포인터 전략을 떠올릴 수 있습니다. 각각을 pt,ps라고 해봅시다. 각 포인터가 가리키는 문자열이 일치할 때는 둘 다 1씩 더해서 다음 문자를 확인하고 다르다면 pt만을 증가시키고 문자열 T가 끝에 다다랐다면 다시 pt를 0으로 초기화 해줍니다.
이렇게 할 경우 다음과 같은 예시에서 비효율적으로 작동하게 됩니다.
zzzz
aaaz
즉 z가 나타나는 위치를 찾기 위해 일일이 T문자열을 탐색하는 대신, 다른 전략을 사용해야 합니다.
이차원 벡터를 활용해 T에서 각 문자가 등장하는 인덱스를 벡터에 순차적으로 담아봅시다. 현재 처리해야하는 문자에 해당하는 벡터에서 pt의 값을 이분탐색하여 다음에 처리해야할 문자가 어디서 등장하는지 찾게 되면 일일이 찾는 것보다 훨씬 빠른속도로 찾을 수 있습니다.
문자열 S마다 최대 T의 길이만큼 이분탐색하므로 시간복잡도는 O(SlogT)입니다.
코드
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < n; ++i)
#define REP(i, n) for (int i = 1; i <= n; ++i)
using namespace std;
string s, t;
vector<int> alpha[26];
int ans = 1, ps, pt, tl, sl;
int main() {
#ifndef ONLINE_JUDGE
freopen("in", "r", stdin);
freopen("out", "w", stdout);
#endif
cin.tie(NULL);
cout.tie(NULL);
ios::sync_with_stdio(false);
cin >> s >> t;
sl = s.size();
tl = t.size();
rep(i, tl) {
alpha[t[i] - 'a'].emplace_back(i);
}
while (ps < sl) {
int x = s[ps] - 'a';
if (alpha[x].empty()) {
cout << -1;
exit(0);
}
int pos = lower_bound(alpha[x].begin(), alpha[x].end(), pt) - alpha[x].begin();
if (pos >= alpha[x].size()) {
ans += 1;
pos = 0;
}
pt = alpha[x][pos];
pt += 1;
ps += 1;
}
cout << ans;
return 0;
}
Read other posts