https://leetcode.com/problems/snakes-and-ladders
- 아래와 같이 Boustrophedon 규칙을 따른다.
➡️ 해당 규칙에 맞게 인덱스를 재정의하자.
➡️ 새로운 인덱스로 board에 해당하는 인덱스를 참조할 수 있게 하자. ex> (새로운 인덱스, board 내 인덱스)
- 각 컬럼에서 이동 가능한 범위와 경우의 수는 정해져 있다.
➡️ 그래프에서 이웃이 결정되어 있는 구조를 떠올릴 수 있다.🧐 그래프 BFS를 이용하자
do 인덱스 to Boustrophedon 인덱스
while(큐가 비어있지 않음){
int 현재인덱스 = 큐.poll();
if(현재인덱스 == n * n) return map.get(현재인덱스)
for(i = 1 to i <= 6){
int 다음인덱스 = 현재인덱스 + i;
if(board[다음인덱스] != -1) next = board[다음인덱스]
if(!map.containsKey(다음인덱스)){
int 현재인덱스까지최소이동거리 = map.get(현재인덱스);
map.put(다음인덱스, 현재인덱스까지최소이동거리 + 1);
q.offer(다음인덱스)
}
}
}
public static int snakesAndLadders(int[][] board) {
// 인덱스 처리
int n = board.length;
int[][] indexes = new int[n * n + 1][2]; // 인덱스 : [x, y]
int index = 1;
boolean isForward = true;
for (int i = n - 1; i >= 0; i--) {
if (isForward) {
for (int j = 0; j < n; j++) {
indexes[index][0] = i;
indexes[index][1] = j;
index++;
}
isForward = false;
} else {
for (int j = n - 1; j >= 0; j--) {
indexes[index][0] = i;
indexes[index][1] = j;
index++;
}
isForward = true;
}
}
Queue<Integer> q = new LinkedList<>();
Map<Integer, Integer> distances = new HashMap<>();
int cur = 1;
q.offer(cur);
distances.put(cur, 0);
while (!q.isEmpty()) {
cur = q.remove();
int distance = distances.get(cur);
if (cur == n * n) return distance;
for (int i = 1; i <= 6; i++) {
int next = cur + i;
if (next > n * n) break;
int r = indexes[next][0];
int c = indexes[next][1];
if (board[r][c] != -1) {
next = board[r][c];
}
if (!distances.containsKey(next)) {
distances.put(next, distance + 1);
q.offer(next);
}
}
}
return -1;
}
public int snakesAndLadders(int[][] board) {
int boardLength = board.length;
int boardArea = boardLength * boardLength;
int[] flatten = new int[boardArea];
boolean[] visisted = new boolean[boardArea];
boolean right = true;
int counter = 0;
// flatten the board into a single dimension
for (int y = boardLength - 1; y >= 0; y--) {
for (int x = 0; x < boardLength; x++) {
int actualX = right ? x : boardLength - 1 - x;
flatten[counter] = board[y][actualX];
counter++;
}
right = !right;
}
int moves = 0;
Queue<Integer> q = new LinkedList<>();
q.add(0);
q.add(null);
while (!q.isEmpty()) {
Integer current = q.poll();
// if null and there are more elements increment and add another null
if (current == null) {
if (!q.isEmpty()) {
q.add(null);
moves++;
}
} else {
// we made it to the end, because this is BFS we can assume this is the best case since we take the values layer by layer
if (current == boardArea - 1) {
return moves;
}
// loop through current + 1 to current + 6 or the end of the board
for (int i = current + 1; i <= Math.min(current + 6, boardArea - 1); i++) {
// if the current space has something other than -1 replace with the actual move
int actualMove = flatten[i] == -1 ? i : flatten[i] - 1;
if (visisted[actualMove]) continue;
visisted[i] = true;
visisted[actualMove] = true;
q.add(actualMove);
}
}
}
return -1;
}
이 문제를 풀면서 가장 고민한 부분은 Boustrophedon 테이블이라는 인덱스 규칙의 특이한 부분을 어떻게 표현할지였다.
나는 그래서 isForword
플래그를 만들어서 해당 두가지 경우에 대한 분기로 For 문을 두 개 정의했다.
그런데 이 풀이는 그렇게 하지 않고 동일한 For문 내에서 연산 규칙을 활용하는 방법으로 풀이했는데, 매우 좋은 배울 점인 것 같다.
나도 이 부분을 꼭 기억해서 다음에 이런 풀이가 필요하면 비슷하게 구현해봐야겠다.
나눗셈 연산으로 표현하기 어려워서 인덱스 규칙을 재구현한것이기 때문에, 나는 이런 풀이가 바람직하지 못한 부분인 줄 알았는데 평탄화 라는 이름도 붙여져 있는 스킬이었다..!
평탄화에 대해 좀 더 알아보고 꼭 머릿속에 담아둬야겠다.