[1406] 에디터 | 백준 실버 2

🔎 문제설명

문제링크

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

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

  • L : 커서를 왼쪽으로 한 칸 옮김 (커서가 문장의 맨 앞이면 무시됨)
  • D : 커서를 오른쪽으로 한 칸 옮김 (커서가 문장의 맨 뒤이면 무시됨)
  • B : 커서 왼쪽에 있는 문자를 삭제함 (커서가 문장의 맨 앞이면 무시됨)
    삭제로 인해 커서는 한 칸 왼쪽으로 이동한 것처럼 나타나지만, 실제 커서 위치는 그대로임
  • P $ : $라는 문자를 커서 왼쪽에 추가함

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

입력

첫째 줄에는 초기에 편집기에 입력되어 있는 문자열이 주어진다. 이 문자열은 길이가 N이다.
둘째 줄에는 입력할 명령어의 개수를 나타내는 정수 M이 주어진다.
셋째 줄부터 M개의 줄에 걸쳐 입력할 명령어가 순서대로 주어진다.

출력

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

제한사항

  • 0 ≤ N ≤ 100,000
  • 문자열은 영어 소문자로만 이루어져 있다.
  • 1 ≤ M ≤ 500,000
  • 명령어는 위의 네 가지 중 하나의 형태로만 주어진다.

🧪 자바 코드

public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        
        LinkedList<Character> sL = new LinkedList<>();
        LinkedList<Character> sR = new LinkedList<>();
        //str.length <= 100,000
        String str = br.readLine(); //스트링 입력
        for(char c : str.toCharArray()){
            sL.add(c);
        }
        //(1 ≤ M ≤ 500,000) 명령어수
        int M = Integer.parseInt(br.readLine());
        while(0 < M--){//sL.size()가 사실 상 커서위치이다.
            char [] cmd = br.readLine().toCharArray();
            if(cmd[0] == 'L' && !sL.isEmpty()) sR.push(sL.removeLast());    //왼쪽마지막->오른쪽첫번째로 이동
            if(cmd[0] == 'D' && !sR.isEmpty()) sL.add(sR.pop());    //오른쪽첫번째->왼쪽마지막으로 이동
            if(cmd[0] == 'B' && !sL.isEmpty()) sL.removeLast(); //왼쪽마지막 제거.
            if(cmd[0] == 'P') sL.add(cmd[2]);   //왼쪽마지막에 밀어넣기
        }
        while(!sL.isEmpty() || !sR.isEmpty()){//sL부터 출력 후 sR 출력
            bw.write( !sL.isEmpty() ? sL.pop() : sR.pop());
        }
        bw.flush();
        bw.close();
}

처음에 컬렉션을 하나만 써서 했는데 시간초과가 나서 두개를 이용해서 풀었습니다.


🧊 파이썬 코드

import sys
import collections as c
stack = c.deque(input()) #문자열 deque로 
input() #명령어 수 
C = len(stack) #커서위치
for cmd in sys.stdin:
    if cmd[0] == 'P':
        stack.append(cmd[2])
        C += 1
    if C and 'L' == cmd[0]:
        stack.rotate(1)
        C -= 1
    if C and 'B' == cmd[0]:
        stack.pop()
        C -= 1
    if cmd[0] == 'D' and C < len(stack):
        stack.rotate(-1)
        C += 1
stack.rotate(C)
print(''.join(stack)) #문자열로 변환

파이썬은 deque를 써서 시간복잡도를 줄일 수 있습니다.
커서가 항상 마지막을 가리키도록 rotate()를 사용합니다. 그리고 명령어가 끝나면 커서위치를 기준으로 돌려 놓습니다.



💡 rotate()

rotate()메서드는 Collection클래스의 deque와 함께 쓸 수 있습니다.

파이썬에서 deque를 쓰는 이유는 list보다 빠르기 때문입니다.

list의 시간복잡도는 O(n)O(n)인 반면, dequeO(1)O(1) 입니다.

따라서 append/remove/push/pop연산이 많이 일어나는 알고리즘에서 deque가 활약할 수 있습니다.

deque에는 rotate()라는 메서드가 있습니다. rotate는 말그대로 순환시켜주는 기능을 갖고있습니다.

예제 코드

from collections import deque
stack = deque([1, 2, 3, 4, 5])

stack.rotate(1) #[5, 1, 2, 3, 4]
stack.rotate(1) #[4, 5, 1, 2, 3]
stack.rotate(-1) #[5, 1, 2, 3, 4]
stack.rotate(-3) #[3, 4, 5, 1, 2]

좋은 웹페이지 즐겨찾기