잘못된 정보가 있다면, 꼭 댓글로 알려주세요(비로그인 익명도 가능).

여러분의 피드백이 저와 방문자 모두를 올바른 정보로 인도할 수 있습니다.

감사합니다. -현록

후원해주실 분은 여기로→

현록의 기록저장소

[Lv3] 카카오프렌즈 컬러링북 본문

Problem Solving/programmers

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

현록 2019. 4. 16. 15:05

https://programmers.co.kr/learn/challenges

 

프로그래밍 강의 | 프로그래머스

기초부터 차근차근, 직접 코드를 작성해 보세요.

programmers.co.kr

문제 설명

 

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

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

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

입력 형식

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

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

출력 형식

리턴 타입은 원소가 두 개인 정수 배열이다. 그림에 몇 개의 영역이 있는지와 가장 큰 영역은 몇 칸으로 이루어져 있는지를 리턴한다.

예제 입출력

m n picture answer
6 4 [[1, 1, 1, 0], [1, 2, 2, 0], [1, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 3], [0, 0, 0, 3]] [4, 5]

예제에 대한 설명

예제로 주어진 그림은 총 4개의 영역으로 구성되어 있으며, 왼쪽 위의 영역과 오른쪽의 영역은 모두 1로 구성되어 있지만 상하좌우로 이어져있지 않으므로 다른 영역이다. 가장 넓은 영역은 왼쪽 위 1이 차지하는 영역으로 총 5칸이다.

 

 


 

상하좌우로 연결되면 연속된 칸으로 보고,

몇 개로 구분된 영역으로 이루어지는지와, 연속된 칸 중 가장 넓은 칸의 칸 수를 구하면 된다.

 

상하좌우로 번져가는 DFS를 구현하면 될 것 같지만, 다음에 의해 메모리 초과가 발생할 수 있습니다.

1 2 3

4 5 6

7 8 9

에서, 2는 좌(1), 우(3), 하(5)로 번지는데,

하로 내려온 5에서도, 우(6)-상(3)을 통해 3이 다시 매겨집니다.

 

물론 boolean[]으로 방문여부를 설정해 재방문 안되게는 할 수 있는데,

그래도 칸이 많을 수록 메모리 초과가 발생할 수 있습니다.

 

다중호출이 아니라, 한번에 탐색하겠습니다.

 

while문 안에 stack을 두어, 상하좌우를 stack에 두고,

stack이 빌 때까지(번져갈 곳이 있을 때까지) boolean[]에 체크해가면서 답을 구해두고,

바깥 for문이 map을 다 탐색하면 끝납니다.

public int[] solution(int m, int n, int[][] picture) {
    boolean[][] check = new boolean[m][n];
    Stack<Integer> toY = new Stack<>();
    Stack<Integer> toX = new Stack<>();
    int count = 0;
    int max = 0;
    for(int i=0;i<m;i++) {
        for(int j=0;j<n;j++) {
            if(!check[i][j] && picture[i][j]!=0) {
                check[i][j] = true;
                int pick = picture[i][j];
                int sum = 1;
                toY.add(i);
                toX.add(j);
                count++;
                while(!toY.isEmpty()) {
                    int y = toY.pop();
                    int x = toX.pop();
                    if(y>0 && !check[y-1][x] && picture[y-1][x]==pick) {
                        toY.add(y-1);
                        toX.add(x);
                        check[y-1][x] = true;
                        sum++;
                    }
                    if(y<m-1 && !check[y+1][x] && picture[y+1][x]==pick) {
                        toY.add(y+1);
                        toX.add(x);
                        check[y+1][x] = true;
                        sum++;
                    }
                    if(x>0 && !check[y][x-1] && picture[y][x-1]==pick) {
                        toY.add(y);
                        toX.add(x-1);
                        check[y][x-1] = true;
                        sum++;
                    }
                    if(x<n-1 && !check[y][x+1] && picture[y][x+1]==pick) {
                        toY.add(y);
                        toX.add(x+1);
                        check[y][x+1] = true;
                        sum++;
                    }
                }
                if(sum>max) max=sum;
            } else check[i][j] = true;
        }
    }
    return new int[] {count, max};
}

stack을 굳이 나누지 않고 Stack<int[]>로 구현할 수 있는데, 하다보니 저렇게 했네요..

'Problem Solving > programmers' 카테고리의 다른 글

[Lv3] 네트워크  (0) 2019.04.16
[Lv3] N으로 표현  (0) 2019.04.16
[Lv2] 점프와 순간이동  (1) 2019.04.15
[Lv2] 소수 만들기  (0) 2019.04.15
[Lv2] 짝지어 제거하기  (0) 2019.04.15
Comments

잘못된 정보가 있다면, 꼭 댓글로 알려주세요(비로그인 익명도 가능).

여러분의 피드백이 저와 방문자 모두를 올바른 정보로 인도할 수 있습니다.

감사합니다. -현록

후원해주실 분은 여기로→