Post

백준 자바 입출력 템플릿

류호석님의 자바 템플릿

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
48
49
50
51
52
53
54
import java.io.*;
import java.util.StringTokenizer;

public class Main {
    static FastReader scan = new FastReader();
    //정답은 sb에 append 를 사용하여 출력
    //만약 개행까지 출력하고 싶으면 append('\n')을 추가
    static StringBuilder sb = new StringBuilder();

    public static void main(String[] args) {
        input();
    }
    static void input(){

    }
    static class FastReader {
        BufferedReader br;
        StringTokenizer st;
        public FastReader() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }
        public FastReader(String s) throws FileNotFoundException {
            br = new BufferedReader(new FileReader(new File(s)));
        }
        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }
        int nextInt() {
            return Integer.parseInt(next());
        }
        long nextLong() {
            return Long.parseLong(next());
        }
        double nextDouble() {
            return Double.parseDouble(next());
        }
        String nextLine() {
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }
    }
}


분석

  • 자바에서 가장 성능이 좋은 입력 처리 방식 중 하나인 BufferedReader 를 사용했다.
    • BufferedReader 는 대량의 데이터를 읽을 때, 특히 텍스트 데이터를 처리할 때 효과적이다.
  • 기본적으로 문자 읽기로 사용되도록 설계되었으며, 파일을 읽는 경우를 위한 생성자도 준비되어 있다.
  • 정의된 FastReader 클래스의 객체인 scan을 통해 쉽게 입력을 받을 수 있다.
  • 출력을 위한 StringBuilder도 객체로 미리 생성되어 있다.
  • FastReader는 기본적으로 다음 단어 하나를 읽는 next() 와 다음 문장 1줄을 읽는 nextLine() 이 구현되어 있다.
  • 그 외에 각 타입에 맞게 next() 를 사용하여 파싱하는 nextInt(), nextLong(), nextDouble() 이 있다.


BufferedReader

  • 기존 입력 방식에서의 문제는 너무 느리다는 것이다.
  • 구조적으로 문제가 있었는데, 바이트 단위로 데이터를 읽을 때마다 시스템을 호출했기 때문이다.
  • 반면에 BufferedReader는 한번에 한 줄의 데이터를 읽기 때문에 성능이 우세할 수 밖에 없었다.
  • 내부적으로 버퍼를 사용하여 데이터를 저장한다.
  • BufferedReader는 문자 기반 스트림으로 바이트는 읽지 못한다.


InputStreamReader

  • BufferedReader는 바이트는 읽지 못하기 때문에 입력 데이터(바이트 스트림)을 문자 데이터(문자 스트림)으로 바꿔줘야 한다.
  • InputStreamReader는 이 변환 과정을 담당한다.


StringBuilder

  • 백준에서 결과를 출력하기 위해 문자열을 구성해야 하는 상황에서 StringBuilder가 좋은 성능을 보인다.
  • String 객체는 때문에 어떤 문자열 객체에 수정을 가하면 사실은 새로운 String 객체가 생성되고 할당되는 것이다.
  • 이전에 있었던 객체는 GC의 대상이 되고 이러한 과정은 많은 리소스를 소모할 수 밖에 없다.
  • 그러나 StringBuilder 는 가변적이어서 새로 객체를 생성하지도 않고 GC에도 부담을 주지 않는다. 뿐만 아니라 문자열을 다루기 위한 다양한 기능을 지원한다.


사용 예시(BOJ 1021)

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import java.io.*;
import java.util.LinkedList;
import java.util.StringTokenizer;

public class Main {
    static FastReader scan = new FastReader();
    static StringBuilder sb = new StringBuilder();

    // 실제 코드 작성은 여기서부터
    static int n, m;
    static LinkedList<Integer> deque = new LinkedList<>();
    static int result=0;

    public static void main(String[] args) {
        input();
        System.out.println(result);
    }
    static void input(){
        n = Integer.parseInt(scan.next());
        m = Integer.parseInt(scan.next());

        for (int i=1;i<=n;i++){
            deque.offerLast(i);
        }

        for (int i=0;i<m;i++){
            solve(Integer.parseInt(scan.next()));
        }
    }
    static void solve(int num){
        int now = deque.indexOf(num);
        int mid = deque.size()/2;
        if (now == 0){
            poll();
        } else if (now<=mid) {
            left(now);
        }else{
            right(deque.size()-now);
        }
    }
    static void poll(){
        deque.pollFirst();
    }
    static void left(int it){
        for (int i=0;i<it;i++){
            deque.offerLast(deque.pollFirst());
            result++;
        }
        poll();
    }
    static void right(int it){
        for (int i=0;i<it;i++){
            deque.offerFirst(deque.pollLast());
            result++;
        }
        poll();
    }
    // 여기까지다.

    static class FastReader {
        BufferedReader br;
        StringTokenizer st;
        public FastReader() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }
        public FastReader(String s) throws FileNotFoundException {
            br = new BufferedReader(new FileReader(new File(s)));
        }
        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }
        int nextInt() {
            return Integer.parseInt(next());
        }
        long nextLong() {
            return Long.parseLong(next());
        }
        double nextDouble() {
            return Double.parseDouble(next());
        }
        String nextLine() {
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }
    }
}
  • input 함수에서 입력들을 받고 solve 함수를 만들어 문제풀이를 위한 로직을 작성한다.
  • 필요에 따라 전역변수나 메서드를 추가 생성한다.
This post is licensed under CC BY 4.0 by the author.