📌 문제 링크:
퍼즐 조각 채우기 - 프로그래머스
game_board
가 주어지고, 퍼즐 조각(1)으로 이루어진 table
이 주어진다. table
에 있는 퍼즐 조각을 회전하여 game_board
의 빈칸을 채울 수 있다. Set<String>
을 사용하여 퍼즐 비교✔ 각 퍼즐을 DFS
로 탐색한 후, 문자열(StringBuilder
)로 변환하여 Set
에 저장
✔ 회전 시 Set
에 저장된 문자열과 비교하여 빈칸을 채우는 방식
❌ 문제점
Set
만 사용하면 회전된 상태를 고려할 수 없음. Map<Integer, Set<String>>
을 활용하여 회전된 퍼즐 관리✔ 각 퍼즐 조각을 Map<Integer, Set<String>>
으로 저장하여 개수 관리
✔ 퍼즐 회전 시 문자열 비교 후, 사용 가능한 퍼즐을 제거하는 방식
❌ 문제점
DFS
탐색 과정에서 방향을 문자열로 저장할 때, "12"라는 문자열이 1 → 2로 탐색한 것인지, 1에서 재귀가 끝나고 다시 2로 이동한 것인지 구분할 수 없음. DFS
탐색 경로의 끝을 명확히 하기 위해 문자열에 .
추가✔ DFS 탐색 과정에서 sb.append(".")
을 추가하여 탐색이 종료된 지점을 명확히 구분
✔ 탐색이 끝날 때마다 .
을 붙이면 동일한 퍼즐의 탐색 경로를 유일하게 만들 수 있음.
❌ 문제점
Set<String>
을 사용하여 퍼즐을 비교하는 과정에서 같은 모양의 퍼즐을 중복으로 인식하는 문제가 남아 있음. moveHistory
에 저장✔ 각 퍼즐 조각에 라벨을 부여하고, moveHistory[label]
에 저장하여 중복 관리
✔ 각 퍼즐 조각을 4방향으로 회전하며 Set<String>
에 저장하여 중복 제거
❌ 문제점
game_board
의 빈칸과 퍼즐 조각을 매칭하는 과정에서 퍼즐이 올바르게 채워지지 않는 버그 발생 DFS
를 수행한 후, Set<String>
을 활용하여 퍼즐 회전 관리✔ 각 퍼즐을 4번 회전하며 가능한 모든 모양을 Set<String>
에 저장
✔ game_board
에서 빈칸을 탐색할 때, moveHistory
에서 일치하는 퍼즐을 찾아 사용
✅ 최종적으로 모든 퍼즐을 정확하게 빈칸에 맞출 수 있도록 최적화 완료! 🚀
import java.util.*;
class Solution {
int[] dix = {-1, 0, 1, 0}; // 상, 우, 하, 좌
int[] diy = {0, 1, 0, -1};
Set<String>[] moveHistory;
int n;
StringBuilder sb = new StringBuilder();
int answer = 0;
int blockSize = 1;
boolean[] isUsed;
public int solution(int[][] game_board, int[][] table) {
n = table.length;
addLabel(table);
moveHistory = new Set[blockSize + 1];
for (int i = 0; i <= blockSize; i++) {
moveHistory[i] = new HashSet<>();
}
isUsed = new boolean[blockSize + 1];
// 회전하며 퍼즐 탐색 및 저장
searchDownRight(table, 0);
searchRightUp(table, 1);
searchUpLeft(table, 2);
searchLeftDown(table, 3);
searchGameBoard(game_board);
return answer / 2; // 좌표를 2배로 관리했으므로 나누기 2
}
private void addLabel(int[][] table) {
boolean[][] visited = new boolean[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (table[i][j] == 1 && !visited[i][j]) {
visited[i][j] = true;
table[i][j] = blockSize;
labelDfs(i, j, 0, visited, table);
blockSize++;
}
}
}
}
private void searchGameBoard(int[][] game_board) {
boolean[][] visited = new boolean[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (game_board[i][j] == 0 && !visited[i][j]) {
visited[i][j] = true;
dfs(i, j, 1, visited, game_board, 0);
String result = sb.toString();
sb.setLength(0);
for (int k = 1; k <= blockSize; k++) {
if (!isUsed[k] && moveHistory[k].contains(result)) {
isUsed[k] = true;
answer += result.length() + 2;
break;
}
}
}
}
}
}
private void dfs(int x, int y, int wall, boolean[][] visited, int[][] table, int turn) {
for (int i = 0; i < 4; i++) {
int dx = x + dix[(i - turn + 4) % 4];
int dy = y + diy[(i - turn + 4) % 4];
if (dx < 0 || dy < 0 || dx >= n || dy >= n) continue;
if (visited[dx][dy]) continue;
if (table[dx][dy] == wall) continue;
visited[dx][dy] = true;
sb.append(i);
dfs(dx, dy, wall, visited, table, turn);
sb.append(".");
}
}
}
✔ 퍼즐 조각을 DFS
탐색 후, 문자열(StringBuilder
)로 저장하여 비교
✔ Set<String>
을 사용하여 퍼즐 회전 시 중복 제거
✔ 각 퍼즐에 라벨을 부여하여 관리 (blockSize
활용)
✔ 빈칸을 탐색하여 퍼즐 조각과 매칭 후, 최적의 조합 찾기