https://www.acmicpc.net/problem/28278

문제 자체는 어렵지 않았다. 초반에는 입력 값이 수이고, 두개 이상일 경우에만 두 번째 값이 명령이라고 생각해서 결과값이 다르게 나왔었지만, 문제를 다시 읽어보니 입력값이 전부 '명령'이었다.

하지만, 시간 초과가 떴다.. 그래서 System.out.println()을 StringBuilder로 바꿔 제출하였더니 정답이 떴다.

그래서 System.out.print와 StringBuilder의 차이점을 공부해 보았다.

System.out.println()

println이 정의된 함수는 다음과 같다.

 public void println(int x) {
        if (getClass() == PrintStream.class) {
            writeln(String.valueOf(x));
        } else {
            synchronized (this) {
                print(x);
                newLine();
            }
        }
    }

코드 내부를 보면, synchronized가 사용되고, 그 안에 print가 있는 것을 알 수 있다. synchronized는 동기화를 의미하며, 작업 중인 스레드의 작업이 끝날 때 까지 다른 데이터에서 공유 데이터에 접근하지 못하도록 하는 것이다.
그렇기 때문에 작업이 끝나기 전 까지 다른 스레드의 대기시간이 발생하고, 그래서 오버해드가 무조건 발생하게 된다.

StringBuilder

 @Override
    public AbstractStringBuilder append(CharSequence s) {
        if (s == null) {
            return appendNull();
        }
        if (s instanceof String) {
            return this.append((String)s);
        }
        if (s instanceof AbstractStringBuilder) {
            return this.append((AbstractStringBuilder)s);
        }
        return this.append(s, 0, s.length());
    }

StringBuilder는 append메소드를 통하여 계속 문자열을 붙여나간다. 이후 이 문자열을 마지막에 한 번만 출력해 주면 된다.

즉, 멀티스레드에서 동기화 발생하지 않아 시간이 훨씬 빠르다.

위의 문제도 print를 사용하면 배열에서 각각 입력이 들어옴과 동시에 출력이 발생하는데 StringBuilder를 사용하면 문자열이 붙어 있다가 마지막에 한 번 결과의 전체가 출력되므로 시간이 더 빠른 것이다.

정답 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();

        int N = Integer.parseInt(br.readLine()); //명령의 수
        Stack<Integer> stack = new Stack<>();

        for (int i = 0; i < N; i++) {
            String[] input = br.readLine().split(" "); //명령
            int order = Integer.parseInt(input[0]); //명령의 종류

            switch (order) {
                case 1:
                    int num = Integer.parseInt(input[1]); //스택에 넣을 수
                    stack.push(num);
                    break;
                case 2:
                    if (stack.isEmpty()) { //스택이 비어 있으면
                        sb.append(-1).append("\n");
                    } else {
                        sb.append(stack.pop()).append("\n"); //맨 위의 정수 출력 후 제거
                    }
                    break;
                case 3:
                    sb.append(stack.size()).append("\n");
                    break;
                case 4:
                    if (stack.isEmpty()) { //스택이 비어 있으면
                        sb.append(1).append("\n");
                    } else {
                        sb.append(0).append("\n");
                    }
                    break;
                case 5:
                    if (!stack.isEmpty()) { //스택이 비어있지 않다면
                        sb.append(stack.peek()).append("\n");
                    } else {
                        sb.append(-1).append("\n");
                    }
                    break;
            }
        }
        br.close();
        System.out.print(sb);
    }
}

profile
컴퓨터가 이해하는 코드는 바보도 작성할 수 있다. 사람이 이해하도록 작성하는 프로그래머가 진정한 실력자다. -마틴 파울러

0개의 댓글