https://school.programmers.co.kr/learn/courses/30/lessons/84021
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
예전에 풀다가 빡구현에 지쳐서 포기한 문제인데 이번엔 풀었다..! 아이디어 자체는 간단하다.
- bfs를 통해 퍼즐과 빈칸들을 찾는다. 그리고 나중에 빈칸에 퍼즐을 넣을 수 있는지 비교해야 하므로 퍼즐과 빈칸의 위치를 0, 0을 시작으로 하며, 딱 맞는 크기의 배열로 만들어야 한다.
- 그리고 각 빈칸에 각 퍼즐들이 들어갈 수 있는지 확인한다.
- 빈칸과 퍼즐의 사이즈는 딱 맞아야 한다.
- 즉, 두 배열의 가로, 세로 길이가 같아야 한다. 그리고 모든 배열 안의 값이 같아야 한다.
- 위 두개의 조건을 모두 만족해야 딱 맞다고 할 수 있다.
아이디어는 간단한데 빡구현이라 어려웠다.. 그리고 내가 실수했던 부분은 다음과 같다.
- 만약 빈칸에 퍼즐이 딱 맞아서 채워 넣었으면, puzzleList에서 해당 퍼즐을 지워줘야 한다. 다음 빈칸들에 퍼즐을 채울 때 이미 빈칸을 채우는데 사용한 퍼즐은 제외해야 하기 때문이다.
import java.util.*;
class Solution {
int n;
int[][] game_board;
int[][] table;
boolean[][] visited_table;
boolean[][] visited_board;
int[] dx = {1, -1, 0, 0};
int[] dy = {0, 0, 1, -1};
List<int[][]> puzzleList = new ArrayList<>();
List<int[][]> boardList = new ArrayList<>();
int answer;
public int solution(int[][] game_board, int[][] table) {
this.game_board = game_board;
this.table = table;
n = game_board.length;
visited_table = new boolean[n][n];
visited_board = new boolean[n][n];
// 1. bfs로 퍼즐 찾기
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (table[i][j] == 1 && !visited_table[i][j]) {
bfsForPuzzle(i, j);
}
}
}
// 2. bfs로 게임 보드의 빈 칸 찾기
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (game_board[i][j] == 0 && !visited_board[i][j]) {
bfsForBoard(i, j);
}
}
}
// 3. 보드에 퍼즐 넣기
for (int[][] board : boardList) {
for (int[][] puzzle : puzzleList) {
boolean isPut = putPuzzle(board, puzzle);
if (isPut) {
puzzleList.remove(puzzle);
break;
}
}
}
return answer;
}
public void bfsForPuzzle(int y, int x) {
List<Node> list = new ArrayList<>();
Queue<Node> que = new LinkedList<>();
que.add(new Node(y, x));
visited_table[y][x] = true;
list.add(new Node(y, x));
int minX = x;
int minY = y;
int maxX = x;
int maxY = y;
while (!que.isEmpty()) {
Node now = que.poll();
for (int i = 0; i < 4; i++) {
int nx = dx[i] + now.x;
int ny = dy[i] + now.y;
if (nx < 0 || nx >= n || ny < 0 || ny >= n || table[ny][nx] != 1 || visited_table[ny][nx]) {
continue;
}
que.add(new Node(ny, nx));
visited_table[ny][nx] = true;
list.add(new Node(ny, nx));
minX = Math.min(minX, nx);
maxX = Math.max(maxX, nx);
minY = Math.min(minY, ny);
maxY = Math.max(maxY, ny);
}
}
// list에 있는 값들을 통해 딱 맞는 배열 만들기 (퍼즐 위치한 곳 = 1)
int[][] puzzle = new int[maxY - minY + 1][maxX - minX + 1];
for (Node node : list) {
puzzle[node.y - minY][node.x - minX] = 1;
}
puzzleList.add(puzzle);
}
public void bfsForBoard(int y, int x) {
List<Node> list = new ArrayList<>();
Queue<Node> que = new LinkedList<>();
que.add(new Node(y, x));
visited_board[y][x] = true;
list.add(new Node(y, x));
int minX = x;
int minY = y;
int maxX = x;
int maxY = y;
while (!que.isEmpty()) {
Node now = que.poll();
for (int i = 0; i < 4; i++) {
int nx = dx[i] + now.x;
int ny = dy[i] + now.y;
if (nx < 0 || nx >= n || ny < 0 || ny >= n || game_board[ny][nx] != 0 || visited_board[ny][nx]) {
continue;
}
que.add(new Node(ny, nx));
visited_board[ny][nx] = true;
list.add(new Node(ny, nx));
minX = Math.min(minX, nx);
maxX = Math.max(maxX, nx);
minY = Math.min(minY, ny);
maxY = Math.max(maxY, ny);
}
}
// list에 있는 값들을 통해 딱 맞는 배열 만들기 (빈 칸 = 1)
int[][] board = new int[maxY - minY + 1][maxX - minX + 1];
for (Node node : list) {
board[node.y - minY][node.x - minX] = 1;
}
boardList.add(board);
}
private boolean putPuzzle(int[][] board, int[][] puzzle) {
for (int i = 0; i < 4; i++) {
if (canPut(board, puzzle)) {
return true;
} else {
puzzle = turn(puzzle);
}
}
return false;
}
private boolean canPut(int[][] board, int[][] puzzle) {
// 1. 사이즈가 맞는지
int boardY = board.length;
int boardX = board[0].length;
int puzzleY = puzzle.length;
int puzzleX = puzzle[0].length;
if ((boardY != puzzleY) || (boardX != puzzleX)) {
return false;
}
// 2. 퍼즐 위치와 빈칸의 위치가 맞는지
int cnt = 0;
for (int i = 0; i < boardY; i++) {
for (int j = 0; j < boardX; j++) {
if (board[i][j] != puzzle[i][j]) {
return false;
}
if (puzzle[i][j] == 1) {
cnt++;
}
}
}
answer += cnt;
return true;
}
// 회전한 새로운 배열을 만들어서 반환
private int[][] turn(int[][] puzzle) {
int[][] newPuzzle = new int[puzzle[0].length][puzzle.length];
for (int i = 0; i < puzzle.length; i++) {
for (int j = 0; j < puzzle[0].length; j++) {
if (puzzle[i][j] == 1) {
newPuzzle[j][puzzle.length - i - 1] = 1;
}
}
}
return newPuzzle;
}
public class Node {
int y, x;
public Node(int y, int x) {
this.y = y;
this.x = x;
}
}
}
'CS > Algorism' 카테고리의 다른 글
99클럽 코테 스터디 13일차 TIL: [프로그래머스] 아이템 줍기 (1) | 2024.06.01 |
---|---|
99클럽 코테 스터디 12일차 TIL: [프로그래머스] 여행경로 (0) | 2024.05.31 |
99클럽 코테 스터디 10일차 TIL: [프로그래머스] 전력망을 둘로 나누기 (0) | 2024.05.29 |
99클럽 코테 스터디 9일차 TIL: [프로그래머스] 모음사전 (0) | 2024.05.28 |
99클럽 코테 스터디 8일차 TIL: [LeetCode] 899. Orderly Queue (0) | 2024.05.27 |