일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 백준 16236
- MySQL
- java 기술면접
- with recursive
- Spring
- java
- Spring Boot
- 웹어플리케이션 서버
- 파이썬
- 백준 19238
- 프로그래머스
- Coroutine
- sql 기술면접
- Kotlin
- 백준
- 백준 16719
- JVM
- 프로래머스
- 백준 16235
- 백준 17779
- re.split
- MSA
- spring oauth
- 백준 15685
- JPA
- 백준 파이썬
- spring cloud
- springboot
- 백준 17626
- spring security
- Today
- Total
시작이 반
[프로그래머스] 퍼즐 조각 채우기 (Java 자바) 본문
문제 설명
테이블 위에 놓인 퍼즐 조각을 게임 보드의 빈 공간에 적절히 올려놓으려 합니다. 게임 보드와 테이블은 모두 각 칸이 1x1 크기인 정사각 격자 모양입니다. 이때, 다음 규칙에 따라 테이블 위에 놓인 퍼즐 조각을 게임 보드의 빈칸에 채우면 됩니다.
- 조각은 한 번에 하나씩 채워 넣습니다.
- 조각을 회전시킬 수 있습니다.
- 조각을 뒤집을 수는 없습니다.
- 게임 보드에 새로 채워 넣은 퍼즐 조각과 인접한 칸이 비어있으면 안 됩니다.
다음은 퍼즐 조각을 채우는 예시입니다.
위 그림에서 왼쪽은 현재 게임 보드의 상태를, 오른쪽은 테이블 위에 놓인 퍼즐 조각들을 나타냅니다. 테이블 위에 놓인 퍼즐 조각들 또한 마찬가지로 [상,하,좌,우]로 인접해 붙어있는 경우는 없으며, 흰 칸은 퍼즐이 놓이지 않은 빈 공간을 나타냅니다. 모든 퍼즐 조각은 격자 칸에 딱 맞게 놓여있으며, 격자 칸을 벗어나거나, 걸쳐 있는 등 잘못 놓인 경우는 없습니다.
이때, 아래 그림과 같이 3,4,5번 조각을 격자 칸에 놓으면 규칙에 어긋나므로 불가능한 경우입니다.
- 3번 조각을 놓고 4번 조각을 놓기 전에 위쪽으로 인접한 칸에 빈칸이 생깁니다.
- 5번 조각의 양 옆으로 인접한 칸에 빈칸이 생깁니다.
다음은 규칙에 맞게 최대한 많은 조각을 게임 보드에 채워 넣은 모습입니다.
최대한 많은 조각을 채워 넣으면 총 14칸을 채울 수 있습니다.
현재 게임 보드의 상태 game_board, 테이블 위에 놓인 퍼즐 조각의 상태 table이 매개변수로 주어집니다. 규칙에 맞게 최대한 많은 퍼즐 조각을 채워 넣을 경우, 총 몇 칸을 채울 수 있는지 return 하도록 solution 함수를 완성해주세요.
제한사항
- 3 ≤ game_board의 행 길이 ≤ 50
- game_board의 각 열 길이 = game_board의 행 길이
- 즉, 게임 보드는 정사각 격자 모양입니다.
- game_board의 모든 원소는 0 또는 1입니다.
- 0은 빈칸, 1은 이미 채워진 칸을 나타냅니다.
- 퍼즐 조각이 놓일 빈칸은 1 x 1 크기 정사각형이 최소 1개에서 최대 6개까지 연결된 형태로만 주어집니다.
- table의 행 길이 = game_board의 행 길이
- table의 각 열 길이 = table의 행 길이
- 즉, 테이블은 game_board와 같은 크기의 정사각 격자 모양입니다.
- table의 모든 원소는 0 또는 1입니다.
- 0은 빈칸, 1은 조각이 놓인 칸을 나타냅니다.
- 퍼즐 조각은 1 x 1 크기 정사각형이 최소 1개에서 최대 6개까지 연결된 형태로만 주어집니다.
- game_board에는 반드시 하나 이상의 빈칸이 있습니다.
- table에는 반드시 하나 이상의 블록이 놓여 있습니다.
입출력 예
game_board | table | result |
[[1,1,0,0,1,0],[0,0,1,0,1,0],[0,1,1,0,0,1],[1,1,0,1,1,1],[1,0,0,0,1,0],[0,1,1,1,0,0]] | [[1,0,0,1,1,0],[1,0,1,0,1,0],[0,1,1,0,1,1],[0,0,1,0,0,0],[1,1,0,1,1,0],[0,1,0,0,0,0]] | 14 |
[[0,0,0],[1,1,0],[1,1,1]] | [[1,1,1],[1,0,0],[0,0,0]] | 0 |
import java.util.*;
class Solution {
int[] dx = {-1, 0, 1, 0};
int[] dy = {0, 1, 0, -1};
public int solution(int[][] game_board, int[][] table) {
int answer = -1;
boolean[][] visitedTable = new boolean[table.length][table.length];
boolean[][] visitedBoard = new boolean[game_board.length][game_board.length];
List<List<int[]>> boardList = new ArrayList<>();
List<List<int[]>> tableList = new ArrayList<>();
for (int i = 0; i < table.length; i++){
for (int j = 0; j < table.length; j++){
if (table[i][j] == 1 && !visitedTable[i][j]){
bfs(i, j, visitedTable, table, 1, tableList);
}
if (game_board[i][j] == 0 && !visitedBoard[i][j]){
bfs(i, j, visitedBoard, game_board, 0, boardList);
}
}
}
answer = findBlock(boardList, tableList);
return answer;
}
public int findBlock(List<List<int[]>> board, List<List<int[]>> table){
int size = 0;
int tableLen = table.size();
int boardLen = board.size();
boolean[] visitedBoard = new boolean[boardLen];
for (int i = 0; i < tableLen; i++){
List<int[]> tablePoints = table.get(i);
for (int j = 0; j < boardLen; j++){
List<int[]> boardPoints = board.get(j);
if (tablePoints.size() == boardPoints.size() && !visitedBoard[j]){ //좌표 개수 같을때
if(isRotate(boardPoints, tablePoints)){ //회전해서 맞는지 확인
size += tablePoints.size();
visitedBoard[j] = true;
break;
}
}
}
}
return size;
}
public boolean isRotate(List<int[]> board, List<int[]> table){
boolean isCollect = false;
board.sort((o1, o2) -> {
return o1[0] > o2[0]?1 : o1[0] < o2[0]?-1 : Integer.compare(o1[1], o2[1]);
});
for (int i = 0; i < 4; i++){ //table퍼즐 0, 90, 180, 270도 회전
table.sort((o1, o2) -> {
return o1[0] > o2[0]?1 : o1[0] < o2[0]?-1 : Integer.compare(o1[1], o2[1]);
});
int nearZeroX = table.get(0)[0];
int nearZeroY = table.get(0)[1];
for (int j = 0; j < table.size(); j++){
table.get(j)[0] -= nearZeroX;
table.get(j)[1] -= nearZeroY;
}
boolean isCollectPoint = true;
for (int j = 0; j < board.size(); j++){ //좌표 비교
int[] boardPoint = board.get(j);
int[] tablePoint = table.get(j);
if (boardPoint[0] != tablePoint[0] || boardPoint[1] != tablePoint[1]){
isCollectPoint = false;
break;
}
}
if (isCollectPoint){
isCollect = true;
break;
} else{ //90도 회전 : x,y -> y, -x
for(int j = 0; j < table.size(); j++){
int temp = table.get(j)[0];
table.get(j)[0] = table.get(j)[1];
table.get(j)[1] = -temp;
}
}
}
return isCollect;
}
public void bfs(int currentX, int currentY, boolean[][] visited, int[][] graph,
int blockOrEmpty, List<List<int[]>> list){
Queue<int[]> queue = new LinkedList<>();
visited[currentX][currentY] = true;
queue.add(new int[]{currentX, currentY});
List<int[]> subList = new ArrayList<>();
subList.add(new int[]{currentX-currentX, currentY-currentY});
while (!queue.isEmpty()){
int[] pop = queue.remove();
int popX = pop[0];
int popY = pop[1];
for (int i = 0; i < 4; i++){
int nextX = popX + dx[i];
int nextY = popY + dy[i];
if (nextX < 0 || nextX >= graph.length || nextY < 0 || nextY >= graph.length){
continue;
}
if (!visited[nextX][nextY] && graph[nextX][nextY] == blockOrEmpty){
visited[nextX][nextY] = true;
queue.add(new int[]{nextX, nextY});
subList.add(new int[]{nextX-currentX, nextY-currentY});
}
}
}
list.add(subList);
}
}
핵심 코드, 푸는법:
퍼즐빈칸, 조각 좌표 구하기 : BFS - queue
좌표 90도 회전 -> x, y = y, -x
회전후 왼쪽위 좌표 기준으로 정렬 and 왼쪽위 좌표를 0, 0으로 계산
'알고리즘 > Programmers' 카테고리의 다른 글
[프로그래머스] 직업군 추천하기 (Java 자바) (0) | 2021.08.23 |
---|---|
[프로그래머스] 수식 최대화 (Java 자바) (0) | 2021.08.23 |
[프로그래머스] 거리두기 확인하기 (Java 자바) (0) | 2021.08.22 |
[프로그래머스] [1차] 뉴스 클러스터링 (Java 자바) (0) | 2021.08.22 |
[프로그래머스] 괄호 변환 (Java 자바) (0) | 2021.08.22 |