You are given an n x n
integer matrix board where the cells are labeled from 1
to n2 in a Boustrophedon style starting from the bottom left of the board (i.e. board[n - 1][0]
) and alternating direction each row.
You start on square 1
of the board. In each move, starting from square curr
, do the following:
next
with a label in the range [curr + 1, min(curr + 6, n2)]
.next
has a snake or ladder, you must move to the destination of that snake or ladder. Otherwise, you move to next
.board
square on row r
and column c
has a snake or ladder if board[r][c] != -1
. The destination of that snake or ladder is board[r][c]
. Squares 1
and n2 do not have a snake or ladder.Note that you only take a snake or ladder at most once per move. If the destination to a snake or ladder is the start of another snake or ladder, you do not follow the subsequent snake or ladder.
[[-1,4],[-1,3]]
, and on the first move, your destination square is 2
. You follow the ladder to square 3
, but do not follow the subsequent ladder to 4
.-1
.n == board.length == board[i].length
2 <= n <= 20
board[i][j]
is either -1
or in the range [1, n2]
.1
and n2 do not have any ladders or snakes.class Solution:
def snakesAndLadders(self, board: List[List[int]]) -> int:
문제가 길어보이지만 내용은 간단합니다. 그림과 같은 정사각형 보드가 있다고 할 때, 가장 빠르게 마지막 숫자까지 도달하는 횟수를 반환해야 합니다.
이 때 board
는 지름길(또는 함정으로도 볼 수 있는)이 없는 곳은 -1
, 있는 곳은 이동해야하는 숫자를 값으로 가집니다.
지름길은 1회용이고 만약 마지막 숫자에 도달할 수 없는 경우엔 -1
을 반환합니다.
제가 생각한 코드는 다음과 같습니다.
class Solution:
def rc(self,num: int, L: int):
r = L-1 - (num-1)//L
c = (num-1)%L
if (L-1-r)%2==0:
return (r,c)
return (r,L-1-c)
def snakesAndLadders(self, board: List[List[int]]) -> int:
L = len(board)
q = deque([(0,1)])
visited = set()
while q:
cnt,num = q.popleft()
if num == L*L:
return cnt
if num not in visited:
visited.add(num)
for dice_num in range(1,7):
next_num = num + dice_num
if next_num > L*L:
break
next_r,next_c = self.rc(next_num,L)
if board[next_r][next_c] != -1:
next_num = board[next_r][next_c]
q.append((cnt+1,next_num))
return -1
rc(num,L)
: 숫자num
와 보드의 변 길이L
을 받아서 해당 숫자의 보드판에서 행,열 값을 반환하는 함수입니다.r
는 L-1
에서 값을 빼주는 방식으로 구합니다.c
는 마지막 행을 시작으로 정방향, 역방향으로 값이 바뀝니다. 따라서 정방향으로 정의 후, 마지막 행을 0으로 시작해서 홀수행인지 짝수행인지 판단합니다.L
, 너비 탐색을 위해 (주사위 던진 횟수, 현재 숫자)
를 원소로 가지는 큐 자료형인 q
, 같은 보드 숫자 체크를 막기 위한 visited
를 정의합니다.num not in visited
) 숫자라면 탐색을 시작합니다.for문
을 통해 모두 탐색합니다. 더한 숫자를 next_num
으로 둡니다.next_num
가 보드판 숫자를 넘어가면 for문
을 탈출합니다.next_num
의 보드판에 지름길이 있다면 next_num
을 보드판의 숫자로 재정의합니다.(next_num,던진횟수+1)
을 q
에 추가합니다.while문
을 탈출했다는 것은 모든 경우를 확인해도 마지막까지 도달하지 못했다는 의미이므로 -1
을 반환합니다.너비 탐색으로 방향을 잡고 중복 탐색을 막기 위한 visited
를 사용하자는 방향으로 정한 후부터는 어렵지 않았던 문제입니다.
다만 속도가 느리게 나오길래 좀 더 빠른 사람의 코드를 참고해보니 제 코드의 rc
함수에서 시간이 걸린 듯 합니다. 좀 더 빨랐던 사람들의 코드는 매번 r,c를 구하는 것이 아닌 r,c의 값을 초기화한 후 r,c의 위치에 따라 다음 r,c를 정하는 방식이였습니다.
조건 처리가 많아서 가독성이 떨어져서인지 수학식으로 처리하는게 좀 더 괜찮아 보입니다. (물론 최적화가 중요한 상황이면 당연히 조건문 처리로 해야합니다!)