Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 스프링 핵심 기능
- Spring Boot
- 김영한
- jpa
- AOP
- pointcut
- JPQL
- 스프링 핵심 원리
- spring
- Thymeleaf
- Servlet
- http
- 스프링
- 인프런
- 백준
- springdatajpa
- java
- db
- Greedy
- 그리디
- SpringBoot
- Proxy
- transaction
- Exception
- Android
- QueryDSL
- kotlin
- JDBC
- 자바
- 알고리즘
Archives
- Today
- Total
개발자되기 프로젝트
[프로그래머스] 카카오프레즈 컬러링북 본문
1. 문제
카카오 프렌즈 컬러링북
출판사의 편집자인 어피치는 네오에게 컬러링북에 들어갈 원화를 그려달라고 부탁하여 여러 장의 그림을 받았다.
여러 장의 그림을 난이도 순으로 컬러링북에 넣고 싶었던 어피치는
영역이 많으면 색칠하기가 까다로워 어려워진다는 사실을 발견하고 그림의 난이도를 영역의 수로 정의하였다.
(영역이란 상하좌우로 연결된 같은 색상의 공간을 의미한다.)
그림에 몇 개의 영역이 있는지와 가장 큰 영역의 넓이는 얼마인지 계산하는 프로그램을 작성해보자.
위의 그림은 총 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칸이다.
2. 문제 정리
영역 : 특정 색깔로 동일하게 상 || 하 ||좌 || 우로 연결되어 있는 노드들의 집합
전 영역을 훑면서 현재 값과 동일한지 판단해야 함. ->DFS, BFS 활용하면 좋을듯
- BFS로 구현하자.
- BFS는 너비 우선 탐색으로 Queue 를 사용하여 구현하면 편리하다.
- 현재 노드의 인접한 노드 중 방문을 안한 노드를 찾아 Queue에 넣어둔다.
- Queue의 head에서 노드를 꺼내서 해당 노드에 인접한 노드 중 방문안한 노드를 Queue에 넣음.
- 반복.
- 즉 현재 노드의 인접한 노드를 먼저 탐색함.
- 반면에 DFS의 경우 Branch 하나를 끝까지 탐색하고 다음 분기점에서 다음 branch 탐색
- 방문한 노드는 boolean visited[i][j]에 기록해 두자.
- 만약 현재 노드가 방문한 적이 없고 색이 칠해져 있다면 새로운 영역으로 볼 수 있다.
- 영역의 수 1 증가
- 새로운 영역의 넓이를 확인한다.
- 현재 노드를 기준으로 상하좌우에 같은 색의 노드가 있는지 확인한다.
- 만약 해당 노드가 방문한 적이 없고 색이 동일하다면 같은 영역의 노드이다.
- 해당 노드를 방문하자. Queue에 넣고, visited에 반영해주자.
- 그리고 해당 영역의 넓이를 증가시킨다.
- 인접한 노드를 추가했으면 Ququd의 head에서 node를 하나 꺼내고, 해당 노드를 기준으로 반복.
- Queue가 빌 때 까지 반복한다.
Queue의 의미 : 인접한 노드를 찾을 노드.
Queue가 빈다면 해당 영역에 더이상 인접한 노드가 없는 것 과 같다.
3. 코드 : BFS
import java.util.*;
class Solution {
public int[] solution(int m, int n, int[][] picture) {
int numberOfArea=0;
int maxSizeOfOneArea=0;
boolean[][] visited = new boolean[m][n];
int[] answer = new int[2];
int[] dx = {0, 0, -1, 1};
int[] dy = {-1, 1, 0, 0};
long[][] arr = new long[m][n];
for (int i=0; i<m; i++){
for (int j=0; j<n; j++){
arr[i][j] =picture[i][j];
}
}
for(int i=0; i<m; i++){ //y
for (int j=0; j<n; j++){ //x
if (arr[i][j] != 0 && !visited[i][j]){
//새로운 영역을 찾았다!
numberOfArea++;
//새로운 영역의 넓이 확인.
int size = check(m, n, arr, i, j, visited, dx, dy);
if(size> maxSizeOfOneArea){
maxSizeOfOneArea=size;
}
}
}
}
answer[0] = numberOfArea;
answer[1] = maxSizeOfOneArea;
return answer;
}
/**
* 영역의 넓이 반환.
*/
public int check(int m, int n, long[][] arr, int i, int j, boolean[][] visited, int[] dx, int[] dy) {
int area = 1; //영역이 넓이
long current = arr[i][j];
visited[i][j] = true;
Queue<int[]> queue = new LinkedList<>();
queue.add(new int[]{i, j});
while (!queue.isEmpty()){
int[] point = queue.remove();
//현재 point 주변 같은 색 찾아서 queue에 넣기
for (int k=0; k< 4; k++){
int y = point[0] + dy[k];
int x = point[1] + dx[k];
// 0<=x<=n, 0<=y<=m 범위가 아닌경우 pass
if(x<0 || x>=n || y<0 || y >=m) continue;
if(!visited[y][x] && arr[y][x] == current){
area++;
queue.add(new int[]{y,x});
visited[y][x] = true;
}
}
}
return area;
}
}
4. 코드 : DFS
import java.util.*;
class Solution {
public int[] solution(int m, int n, int[][] picture) {
int numberOfArea=0;
int maxSizeOfOneArea=0;
boolean[][] visited = new boolean[m][n];
int[] answer = new int[2];
int[] dx = {0, 0, -1, 1};
int[] dy = {-1, 1, 0, 0};
long[][] arr = new long[m][n];
for (int i=0; i<m; i++){
for (int j=0; j<n; j++){
arr[i][j] =picture[i][j];
}
}
for(int i=0; i<m; i++){ //y
for (int j=0; j<n; j++){ //x
if (arr[i][j] != 0 && !visited[i][j]){
//새로운 영역을 찾았다!
numberOfArea++;
//새로운 영역의 넓이 확인.
int size = check(m, n, arr, i, j, visited, dx, dy);
if(size> maxSizeOfOneArea){
maxSizeOfOneArea=size;
}
}
}
}
answer[0] = numberOfArea;
answer[1] = maxSizeOfOneArea;
return answer;
}
/**
* 영역의 넓이 반환.
*/
public int check(int m, int n, long[][] arr, int i, int j, boolean[][] visited, int[] dx, int[] dy) {
int area = 1; //영역이 넓이
long current = arr[i][j];
visited[i][j] = true;
// Queue<int[]> queue = new LinkedList<>();
Stack<int[]> stack = new Stack<>();
stack.push(new int[]{i, j});
while (!stack.isEmpty()){
int[] point = stack.pop();
//현재 point 주변 같은 색 찾아서 queue에 넣기
for (int k=0; k< 4; k++){
int y = point[0] + dy[k];
int x = point[1] + dx[k];
// 0<=x<=n, 0<=y<=m 범위가 아닌경우 pass
if(x<0 || x>=n || y<0 || y >=m) continue;
if(!visited[y][x] && arr[y][x] == current){
area++;
stack.push(new int[]{y,x});
visited[y][x] = true;
}
}
}
return area;
}
}
5. DFS, BFS
- DFS, BFS 둘 다 그래프를 탐색하는 방법이다.
- 둘다 방문 여부 기록이 필요하다.
- 두 방법의 차이는 다음에 방문할 노드를 정하는 방법이다.
- 현재 노드를 기준으로 branch를 전부 탐색 후 다음 branch로 넘어가는 방법 -> DFS
- 현재 노드를 기준으로 인접한 노드를 전부 탐색 후 다음 노드로 넘어가는 방법 -> BFS
- 두 방법의 차이는 노드를 담아두는 자료의 형태로 구분이 된다.
- DFS는 Stack으로 구현, BFS는 Queue로 구현한다.
- DFS를 Stack으로 구현하는 이유는
- 현재 분기(node)를 기준으로 한쪽 branch를 탐색했다가 현재 분기(node)로 돌아오기 때문.->push, pop
- 반면 BFS는 현재 노드를 기준으로 주변에 있는 인접 노드를 순서대로 방분 -> enQueue, deQueue
- 결국 방문 노드를 판단하는 기준은 같지만 방문 노드를 담아 둘 자료형의 차이로 구분됨.
6. GitHub: 211219 Coloring book
'코테준비' 카테고리의 다른 글
[프로그래머스] 피보나치 수 (0) | 2021.12.20 |
---|---|
[프로그래머스] JadenCase 문자열 만들기 (0) | 2021.12.20 |
[프로그래머스] 문자열 압축 (0) | 2021.12.17 |
[프로그래머스] 이상한 문자 만들기 (0) | 2021.12.14 |
[프로그래머스] 시저암호 (0) | 2021.12.13 |
Comments