포스트

BOJ 10747 Censoring (Silver)

sorohue가 PS하는 블로그

BOJ 10747 Censoring (Silver)

문제 링크입니다.

문제 요약

주어진 문자열 $S$에서 패턴 $P$를 앞에서부터 찾는 대로 지워나갑니다. 최종 문자열을 구하세요.

풀이

$S$에서 $P$를 찾는 건 KMP로 슥슥하면 됩니다. 찾은 패턴을 $S$에서 날려버린 뒤의 처리만 고민해 보면 됩니다.

KMP의 작동 원리는 문자열의 각 글자마다 다음 글자가 패턴이랑 안 맞으면 어디로 날려보낼 지를 계산하면서 incremental하게 진행하는 방식입니다. 뒤쪽 문자열이 갑자기 바뀐다고 해서 앞쪽의 이미 구해둔 이 값들이 바뀔 일은 없기 때문에, KMP를 돌리다가 패턴을 찾으면 그 패턴을 애초에 없던 것처럼 취급하고 그 전 문자에서 값을 끌어와서 마저 KMP를 진행하면 됩니다. 총 시간 복잡도는 ${\cal O}(\vert S \vert + \vert P \vert)$입니다.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include<bits/stdc++.h>
using namespace std;
deque<char> st;
stack<int> ex;
vector<int> ff;

vector<int> Failure_Function(string s){
	int n = s.size();
	vector<int> pi(n, 0);
	int j = 0;
	for(int i = 1; i < n; i++){
		while(j > 0 && s[i] != s[j]) j = pi[j-1];
		if(s[i] == s[j]){
			pi[i] = ++j;
		}
	}
	return pi;	
}

int main(){
	cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
	string s, explode; cin >> s >> explode;
	ff = Failure_Function(explode);
	ex.push(0);
	for(int i = 0; i < s.length(); i++){
		st.push_back(s[i]);
		int now = ex.top();
		while(now){
			if(explode[now] == s[i]){
				ex.push(now+1);
				break;
			}
			now = ff[now-1];
		}
		if(!now) ex.push(explode[0] == s[i]);
		if(ex.top() == explode.length()){
			for(int e = 0; e < explode.length(); e++){
				ex.pop();
				st.pop_back();
			}
		}
	}
	while(!st.empty()){
		cout << st.front();
		st.pop_front();
	}
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.