[백준][1406번] 에디터
Updated:
시간초과 발생 코드
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String str = br.readLine();
int m = Integer.parseInt(br.readLine());
int idx = str.length(); //커서 위치
List<Character> list = new LinkedList();
for(int i=0; i<str.length(); i++)
list.add(str.charAt(i));
while(m-->0){
String cmd = br.readLine();
if(cmd.startsWith("P")){
char ch = cmd.split(" ")[1].charAt(0);
list.add(idx, ch);
idx++;
}else if(cmd.equals("B")){
if(idx-1 >= 0){
list.remove(idx-1);
idx--;
}
}else if(cmd.equals("L")){
if(idx-1 >= 0){
idx--;
}
}else if(cmd.equals("D")){
if(idx+1<= list.size()){
idx++;
}
}
}
for(char ch: list){
bw.write(ch);
}
bw.flush();
bw.close();
}
}
틀린 이유
ArrayList와 달리 삽입/삭제시 임시배열을 생성하여 밀어내는 식으로 복사하는 방식이아닌
이전과 다음요소의 정보를 활용하여 삽입/삭제를 하기때문에 LinkedList를 선택했었다.
하지만 시간초과가 일어났다.
위 코드에서 LinkedList의 원하는 위치(인덱스)의 삽입/삭제가 이루어지고 있다.
해당 위치까지 찾아가는 작업이 최악의 경우 O(n)의 복잡도를 가지게된다.
즉, 삽입/삭제시 그 인덱스에 바로 접근하는 것이 아니다.
문제의 크기 n은 최대 60만까지 될 수 있기때문에
효율적이지 못하고시간초과의 원인이라고 생각한다.
문제 해결 방법이 떠오르지 않아 구글링을 활용했다.
출처: https://mygumi.tistory.com/62
위 작성자는 대체로 ListIterator를 활용하여 해결하는 방법을 제시했다.
Iterator를 상속한 인터페이스로서 List에 포함된 모든 객체를 양방향으로 탐색하며 객체를 조작하는 방법을 제공한다.
문제의 커서처럼 해당하는 위치에 있으면서 삽입/삭제를 처리할 수 있다.
다른 새로운 방법
이 문제는 stack을 활용해서 해결할 수도 있다.
커서를 기준으로 커서의 왼쪽 스택(left)와 오른쪽 스택(right)로 나누어 풀수있다.
1) L연산
왼쪽 스택의 top데이터를 오른쪽 스택으로 push한다.
복잡도 : O(1)
2) D연산
1과 마찬가지다.
3) B연산
왼쪽 스택 pop()
복잡도 : O(1)
4) P연산
왼쪽 스택에 push
복잡도 : O(1)
다른 풀이
import java.util.*;
import java.io.*;
public class Main {
public static void main(String args[]) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = br.readLine();
Stack<Character> left = new Stack<Character>();
Stack<Character> right = new Stack<Character>();
for (int i=0; i<s.length(); i++) {
left.push(s.charAt(i));
}
int m = Integer.parseInt(br.readLine());
while (m-- > 0) {
String[] line = br.readLine().split(" ");
char what = line[0].charAt(0);
if (what == 'L') {
if (!left.empty()) {
right.push(left.pop());
}
} else if (what == 'D') {
if (!right.empty()) {
left.push(right.pop());
}
} else if (what == 'P') {
char c = line[1].charAt(0);
left.push(c);
} else if (what == 'B') {
if (!left.empty()) {
left.pop();
}
}
}
while (!left.empty()) {
right.push(left.pop());
}
StringBuilder sb = new StringBuilder();
while (!right.empty()) {
sb.append(right.pop());
}
System.out.println(sb);
}
}
느낀점 키워드
- LinkedList에서 remove와 add는 리스트의 처음부터 끝까지 탐색한다는 걸 잊지말자. O(n)의 시간이 걸린다.
- ListIterator을 활용해서 풀수도있다.
- 커서기준 왼쪽,오른쪽 stack을 나누어 LIFO성질을 활용한 방법
Leave a comment