이것저것

BOJ - 1406. 에디터 본문

Problem Solving

BOJ - 1406. 에디터

nays111 2021. 1. 10. 07:20

문제

한 줄로 된 간단한 에디터를 구현하려고 한다. 이 편집기는 영어 소문자만을 기록할 수 있는 편집기로, 최대 600,000글자까지 입력할 수 있다.

이 편집기에는 '커서'라는 것이 있는데, 커서는 문장의 맨 앞(첫 번째 문자의 왼쪽), 문장의 맨 뒤(마지막 문자의 오른쪽), 또는 문장 중간 임의의 곳(모든 연속된 두 문자 사이)에 위치할 수 있다. 즉 길이가 L인 문자열이 현재 편집기에 입력되어 있으면, 커서가 위치할 수 있는 곳은 L+1가지 경우가 있다.

이 편집기가 지원하는 명령어는 다음과 같다.

 

초기에 편집기에 입력되어 있는 문자열이 주어지고, 그 이후 입력한 명령어가 차례로 주어졌을 때, 모든 명령어를 수행하고 난 후 편집기에 입력되어 있는 문자열을 구하는 프로그램을 작성하시오. 단, 명령어가 수행되기 전에 커서는 문장의 맨 뒤에 위치하고 있다고 한다.

입력

첫째 줄에는 초기에 편집기에 입력되어 있는 문자열이 주어진다. 이 문자열은 길이가 N이고, 영어 소문자로만 이루어져 있으며, 길이는 100,000을 넘지 않는다. 둘째 줄에는 입력할 명령어의 개수를 나타내는 정수 M(1 ≤ M ≤ 500,000)이 주어진다. 셋째 줄부터 M개의 줄에 걸쳐 입력할 명령어가 순서대로 주어진다. 명령어는 위의 네 가지 중 하나의 형태로만 주어진다.

출력

첫째 줄에 모든 명령어를 수행하고 난 후 편집기에 입력되어 있는 문자열을 출력한다.

예제 입력 1

abcd 3 P x L P y

예제 출력 1

abcdyx

예제 입력 2

abc 9 L L L L L P x L B P y

예제 출력 2

yxabc

예제 입력 3

dmih 11 B B P x L B B B P y D D P z

사용할 자료구조

커서를 기준으로 왼쪽을 담을 스택, 오른쪽을 담을 스택 두 개의 스택을 만들었습니다.

stack<char> left; stack<char> right;

풀이 과정

  1. 처음 입력받는 문자열은 왼쪽 스택에 순차적으로 담아줍니다. (abcd 인 경우, top이 d 가 되어야함 ⇒ 커서는 명령어가 수행되가 전에 문장의 맨 뒤에 위치하고 있다고 문제에서 언급했기 때문)

for(int i=0;i<str.size();i++){ left.push(str[i]); }

  1. 문제에서의 4가지 명령어

2-1) L : 커서를 왼쪽으로 한 칸 옮기게 되면 커서 기준의 오른쪽 부분은 오른쪽 스택으로 옮겨져야 합니다.

if(command=="L"){ if(!left.empty()){ right.push(left.top()); left.pop(); }

이 때, 문제에서 커서가 문장의 맨 앞이면 무시된다고 했기 때문에 반드시 if(!left.empty()) 조건을 추가해줘야합니다. ⇒ 추가 안할시 스택이 비었음에도 불구하고 top을 가져오려고 하기 때문에 에러가 발생

2-2) D : 커서를 오른쪽으로 한 칸 옮기게 되면 커서 기준의 왼쪽 부분을 왼쪽 스택으로 옮겨야 합니다.

if(command=="D"){ if(!right.empty()){ left.push(right.top()); right.pop(); } }

2-3) B : 커서 왼쪽에 문자를 삭제

if(command=="B"){ if(!left.empty()){ left.pop(); } }

2-2, 2-3도 마찬가지로 스택이 비었는지 안비었는지 검사

2-4) P + char : P가 입력되었을 경우, char를 입력받아 왼쪽 스택에 추가해줍니다.

if(command=="P"){ char ch; cin>>ch; left.push(ch); }

  1. 문제에서 시간 제한이 0.3 초로 주어졌기 때문에 스택을 사용하여 결과를 출력해줘야합니다.

(스택은 top 에 있는 원소만 조회할 수 있으므로 O(1) 만큼 걸립니다.)

//한쪽 스택에 다 담은 다음에 top출력 //커서 왼쪽 스택을 커서 오른쪽 스택에 다 옮기기 while(!left.empty()){ right.push(left.top()); left.pop(); } //커서 오른쪽 스택에서 top 차례대로 출력 while(!right.empty()){ cout<<right.top(); right.pop(); }

시간 복잡도

4가지 연산 (L,D,B,P)를 하는데 모두 O(1) 만큼 걸리고, 답을 출력하는 과정에서도 O(1)만큼 걸립니다.

명령어의 개수를 나타내는 정수 M(1 ≤ M ≤ 500,000) 인데 0.3초 안에 해결해야하므로 반드시 시간복잡도 O(1)로 해결해야하는 문제였습니다.

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <stack>
#include <queue>
#include <map>
#include <functional>
using namespace std;

int main(){
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(false);
    string str;
    cin>>str;
    int n;
    cin>>n;
    stack<char> left;
    stack<char> right;
    //처음엔 커서가 맨 끝에 있으므로 처음 str 모두 왼쪽에 삽입
    for(int i=0;i<str.size();i++){
        left.push(str[i]);
    }
    for(int i=0;i<n;i++){
        string command;
        cin>>command;
        if(command=="P"){
            char ch;
            cin>>ch;
            left.push(ch);
        }else if(command=="L"){
            if(!left.empty()){
                right.push(left.top());
                left.pop();
            }
        }else if(command=="B"){
            if(!left.empty()){
                left.pop();
            }
        }else if(command=="D"){
            if(!right.empty()){
                left.push(right.top());
                right.pop();
            }
        }
    }
    //출력할때 O(1)로 나오게끔 해야댐
    //한쪽 스택에 다 담은 다음에 top출력
    
    //커서 왼쪽 스택을 커서 오른쪽 스택에 다 옮기기
    while(!left.empty()){
        right.push(left.top());
        left.pop();
    }
    //커서 오른쪽 스택에서 top 차례대로 출력
    while(!right.empty()){
        cout<<right.top();
        right.pop();
    }

    return 0;
}

 

'Problem Solving' 카테고리의 다른 글

BOJ - 1715. 카드 정렬하기  (0) 2021.01.10
BOJ - 1935. 후위표기식2  (0) 2021.01.10
BOJ - 2346. 풍선 터뜨리기  (0) 2021.01.10
BOJ - 1158. 요세푸스 문제  (0) 2021.01.10
BOJ - 1021. 회전하는 큐  (0) 2021.01.09
Comments