문제 접근
처음에는 입력 문자열에서 폭발 문자열을 찾은 뒤 삭제하고 삭제한 위치의 전부터 다시 탐색하는 방법으로 O(입력 문자열 길이) 로 풀려고 했는데 문자열을 삭제하는데 시간이 더 오래 걸려 좋은 방법이 아니라고 생각했다. 문자열 알고리즘을 찾아보던 중 보이어-무어 알고리즘에 대해 알게 되어 이 알고리즘의 접근 방법을 살짝 이용했다.
보이어-무어 알고리즘은 문자열을 오른쪽에서 왼쪽으로 비교하고, 이동은 왼쪽에서 오른쪽으로 하는 방식인데 오른쪽 끝의 문자가 일치하지 않고, 끝 문자가 비교 문자열에 존재하지 않으면 비교 문자열 길이만큼 이동하는 알고리즘이다. 끝 문자가 비교 문자열 내에 존재하는 것까지 확인할 필요는 없어보였고, 스택에 넣다가 끝 문자와 같은 문자가 나오면 앞 문자열을 비교한 뒤 비교 문자열과 같으면 그 길이만큼 pop() 하고, 다시 쌓는 방식으로 구현했다. 풀이 후 다른 사람 코드를 확인해보니 더 깔끔하고, 스택을 이용하지 않아도 되는 코드가 있어서 그 방식으로 다시 구현했다.
1. ans 배열의 idx 번째 문자에 입력된 문자열 src 의 i 번째 문자를 대입한다.
2. idx 번째 문자가 폭발 문자열 exp 의 마지막 문자와 같다면, exp 크기가 idx 크기보다 큰 지 확인한다.
3. 크다면 계속 진행하고, 작거나 같다면 ans 와 exp 를 비교한다.
4. ans 의 일부분이 exp 와 같다면 idx 를 exp 의 크기만큼 감소한다. ( 폭발 문자열 제거 )
5. idx 가 0이면 "FRULA" 를 출력하고, 0이 아니라면 ans 를 출력한다.
정리하자면 입력 문자열을 ans 배열에 차례대로 쌓다가 폭발 문자열의 끝자리 문자와 같은 문자가 확인되면 폭발 문자열의 일부인지 확인한 뒤 폭발 문자열이라면 쌓을 위치를 가리키는 idx 를 폭발 문자열 길이만큼 감소해서 제거하는 것이다.
문제 코드
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
ios_base::sync_with_stdio(0);
cin.tie(0);
int idx = 0;
string src, exp;
char ans[1000001];
cin>>src>>exp;
for(int i=0; i<src.size(); ++i)
{
ans[idx++] = src[i];
if(ans[idx-1] == exp[exp.size()-1])
{
if(idx<exp.size())
continue;
bool check = true;
for(int j=0; j<exp.size(); ++j)
{
if(ans[idx-j-1] != exp[exp.size()-j-1])
{
check = false;
break;
}
}
if(check)
idx-=exp.size();
}
}
if(!idx)
cout<<"FRULA\n";
else
{
for(int i=0; i<idx; ++i)
cout<<ans[i];
cout<<'\n';
}
}
'개발 > 알고리즘' 카테고리의 다른 글
백준 4358번 : 생태학 (0) | 2020.09.27 |
---|---|
백준 5052번 : 전화번호 목록 (0) | 2020.09.25 |
백준 1654번 : 랜선 자르기 (0) | 2020.09.17 |
백준 11726번 : 2xn 타일링 (0) | 2020.09.04 |
백준 1620번 : 나는야 포켓몬 마스터 이다솜 (0) | 2020.09.04 |