본문 바로가기
코딩테스트/자바 Level 2

[Java] 카카오 프렌즈 컬러링북

by onggury 2023. 8. 14.

문제

출판사의 편집자인 어피치는 네오에게 컬러링북에 들어갈 원화를 그려달라고 부탁하여 여러 장의 그림을 받았다. 여러 장의 그림을 난이도 순으로 컬러링북에 넣고 싶었던 어피치는 영역이 많으면 색칠하기가 까다로워 어려워진다는 사실을 발견하고 그림의 난이도를 영역의 수로 정의하였다. (영역이란 상하좌우로 연결된 같은 색상의 공간을 의미한다.)

 

그림에 몇 개의 영역이 있는지와 가장 큰 영역의 넓이는 얼마인지 계산하는 프로그램을 작성해보자.

위의 그림은 총 12개 영역으로 이루어져 있으며, 가장 넓은 영역은 어피치의 얼굴면으로 넓이는 120이다.

 

 

제한사항

입력은 그림의 크기를 나타내는 m과 n, 그리고 그림을 나타내는 m × n 크기의 2차원 배열 picture로 주어진다. 제한조건은 아래와 같다.

  • 1 <= m, n <= 100
  • picture의 원소는 0 이상 2^31 - 1 이하의 임의의 값이다.
  • picture의 원소 중 값이 0인 경우는 색칠하지 않는 영역을 뜻한다.

 

import java.util.*;

class Solution {
    public int[] solution(int m, int n, int[][] picture) {
        int[] answer = {0, 0};
        int[][] visited = new int[m][n];
        int[] dx = {1, 0, -1, 0};
        int[] dy = {0, 1, 0, -1};
        Queue<Integer[]> graphQueue = new LinkedList<Integer[]>();
        
        for(int i = 0; i < picture.length; i++) {
            for(int j = 0; j < picture[0].length; j++) {
                if(picture[i][j] == 0) { continue; }  // 색칠된 부분이 아니라면
                if(visited[i][j] == 0) { // 방문하지 않았다면
                    int visiteCount = 0;
                    answer[0]++;
                    graphQueue.add(new Integer[]{i, j});
                    
                    while(graphQueue.size() != 0) {
                        Integer[] cur_node = graphQueue.poll();
                        int cx = cur_node[0];
                        int cy = cur_node[1];
                        
                        for(int d = 0; d < 4; d++) {
                            int nx = cx + dx[d];
                            int ny = cy + dy[d];
                            if(nx < 0 || nx >= picture.length || ny < 0 || ny >= picture[0].length || 
                               picture[nx][ny] != picture[cx][cy] || visited[nx][ny] != 0) {
                                continue;
                            }
                            graphQueue.add(new Integer[]{nx, ny});
                            visited[nx][ny] = 1;
                            visiteCount++;
                        }
                    }
                    answer[1] = Math.max(answer[1], visiteCount);
                }
            }
        }

        return answer;
    }
}

전형적인 BFS 문제이지 않을까 싶다.

 

각 좌표에 대해서 상 하 좌 우 좌표를 방문하면서 연관 있는 데이터라면 큐에 저장하고 방문한 지역은 방문 표시를 해둔다.

만약 상 하 좌 우의 좌표값이 범위를 벗어나거나 이미 방문했거나 연관 없는 좌표라면 해당 작업은 건너뛴다.

 

그렇게 각각 연관 있는 값이 몇 개인지 세다가, 더 이상 방문 할 지역이 없어지면(=주변에 연관있는 데이터가 없다면) 해당 개수를 저장하고 이를 반복하면서 최대 개수를 찾는다.

 

 

이전에 파이썬 코딩테스트 공부를 할 때를 기억하면서 해결했다.

자바로 구현하는 것은 처음이라 아직 많이 미숙하지만 적어도 기본 방법은 알고 있다 보니 응용하는 연습만 많이 해보면 될 것 같다.

 

 

출처

https://school.programmers.co.kr/learn/courses/30/lessons/1829