본문 바로가기
Java

[백준] 코딩테스트 문제 2738: 행렬 덧셈

by 리슈다 2026. 3. 4.

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

import java.util.*;
import java.io.*;
public class Main {
    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();

        int[][] ary1 = new int[n][m];
        int[][] ary2 = new int[n][m];

        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                ary1[i][j] = sc.nextInt();
            }
        }

        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                ary2[i][j] = sc.nextInt();
            }
        }

        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                System.out.print(ary1[i][j] + ary2[i][j] + " ");
            }
            System.out.println();
        }

    }
}

처음 작성한 코드. 일단 문제부터 풀고 성능 향상을 해보자 하고 익숙한 Scanner도 사용하고 StringBuilder 대신 println을 여러번 반복 실행하는 코드로 작성했다. 문제는 맞았고, 아래는 아는 정보들 안에서 리팩토링한 버전

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));
        StringTokenizer st;

        String str = br.readLine();
        st = new StringTokenizer(str);
        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());

        int[][] ary1 = new int[n][m];

        for(int t = 0; t < 2; t++){
            for(int i = 0; i < n; i++){
                st = new StringTokenizer(br.readLine());
                for(int j = 0; j < m; j++){
                    ary1[i][j] = ary1[i][j] + Integer.parseInt(st.nextToken());
                }
            }
        }

        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                sb.append(ary1[i][j]).append(" ");
            }
            sb.append("\n");
        }
        System.out.println(sb);
    }
}

우선 Scanner 대신 BufferedReader 사용해서 속도를 올렸다.

 

Scanner와 BufferedReader / BufferedWriter의 차이점과 사용법

이때까지 귀찮아서 Scanner만 항상 사용했는데, 이제야 정리를 해보고, 오늘 부로 절대 Scanner를 사용하는 과거로 돌아가지 않을 것이다. 1. Scanner Scanner는 띄어쓰기와 개행문자를 경계로 값을 인식

juno-juno.tistory.com

BufferedReader는 문자열을 읽어오는 방식이라 StringTokenizer를 사용해서 공백 기준으로 분리한 뒤 Integer.parseInt() 사용해서 정수로 변환해서 받는다.

 

배열은 굳이 2개를 생성하지 않고, 하나만 생성해서 합을 누적해서 저장했다.

값을 따로 입력 안 하면 배열 안의 값들은 다 0으로 초기화 되므로 입력받은 수들을 바로 덮어써도 무방함

 

배열 2개만 더하는 것은 문제에서 제시됐으니 처음 for문은 2번만 반복

n행에 입력할 수가 같은 줄로 공백 기준으로 입력되므로 st = new StringTokeinzer(br.readLine())을 두번째 for문 안(3번째 for문 밖)에 위치시킨다.

이후 값을 일일히 입력할 3번째 for문에서 배열(int[n][m])에 공백 기준으로 나눠진 값(st.nextToken())을 하나씩 입력한다.

그럼 한 줄에 입력된 3개의 값이 n행에 0부터 m-1열까지 순서대로 입력됨

 

그리고 결과 배열을 StringBuilder 사용해서 반복문 안쪽에선 값들만 sb에 .append() 사용해서 값 하나씩 공백 추가해서 넣고,

(행 하나 다 넣었을 때마다 append("\n")로 줄바꿈 해야함)

출력문은 한 번만 사용해서 출력했다.

 

 

그렇다면 나름 수정한 2번째 코드를 지교수님은 어떻게 보셨을까

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());

        int[][] sum = new int[n][m];

        for (int t = 0; t < 2; t++) {
            for (int i = 0; i < n; i++) {
                st = new StringTokenizer(br.readLine());
                for (int j = 0; j < m; j++) {
                    sum[i][j] += Integer.parseInt(st.nextToken());
                }
            }
        }

        StringBuilder sb = new StringBuilder(n * m * 4); // 대충 넉넉히
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (j > 0) sb.append(' ');
                sb.append(sum[i][j]);
            }
            sb.append('\n');
        }
        System.out.print(sb);
    }
}

1. 불필요한 String 변수 없애고 한 줄로 st = new StringTokenizer(br.readLine()); 으로 사용

2. 덧셈 표현 간결하게 += 사용

3. 출력의 행 끝 공백(append(' ')) 제거

4. StringBuilder의 초기 용량 잡아두기

 

 

그리고 내가 한 방식 외에 그냥 성능, 가독성 좋고 코테에서 점수 잘 받을만한 코드 작성해달라 해봤다.

import java.io.*;

public class Main {

    // 매우 빠른 입력기 (Java 8)
    private static final class FastScanner {
        private final InputStream in;
        private final byte[] buffer = new byte[1 << 16];
        private int ptr = 0, len = 0;

        FastScanner(InputStream in) {
            this.in = in;
        }

        private int readByte() throws IOException {
            if (ptr >= len) {
                len = in.read(buffer);
                ptr = 0;
                if (len <= 0) return -1;
            }
            return buffer[ptr++];
        }

        int nextInt() throws IOException {
            int c;
            do {
                c = readByte();
            } while (c <= ' ' && c != -1);

            int sign = 1;
            if (c == '-') {
                sign = -1;
                c = readByte();
            }

            int val = 0;
            while (c > ' ') {
                val = val * 10 + (c - '0');
                c = readByte();
            }
            return val * sign;
        }
    }

    public static void main(String[] args) throws Exception {
        FastScanner fs = new FastScanner(System.in);

        int n = fs.nextInt();
        int m = fs.nextInt();

        int[][] sum = new int[n][m];

        // A + B를 바로 누적
        for (int t = 0; t < 2; t++) {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    sum[i][j] += fs.nextInt();
                }
            }
        }

        StringBuilder sb = new StringBuilder(n * m * 4);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (j > 0) sb.append(' ');
                sb.append(sum[i][j]);
            }
            sb.append('\n');
        }
        System.out.print(sb);
    }
}

FastScanner는 초면인데

..

다음에 알아보도록 하자.

성능은 좋긴한데, 내 첫 코드에서 수정한 코드의 변화가 더 크다.