#909 Snakes and Ladders
the problem
In plain words
An n × n board numbers its squares 1 to n², starting at the bottom-left and zig-zagging upwards: left → right on the bottom row, right → left on the next, and so on. You start on square 1. Each roll moves you 1 to 6 squares forward (never past n²). If you land on a square whose board[r][c] isn't -1, you must jump to square board[r][c] — a snake or a ladder — but only once per roll, even if that square starts another jump. Return the fewest rolls to reach square n², or -1 if it can't be done.
in board = [[-1,-1,-1,-1,-1,-1],[-1,-1,-1,-1,-1,-1],[-1,-1,-1,-1,-1,-1],[-1,35,-1,-1,13,-1],[-1,-1,-1,-1,-1,-1],[-1,15,-1,-1,-1,-1]]
out 4
Roll to 2 → ladder to 15. Roll to 17 → snake to 13. Roll to 14 → ladder to 35. Roll to 36.
in board = [[-1,-1],[-1,3]]
out 1
Roll a 3 and land on square 4, the last square. (Square 2 has a ladder to 3, but that doesn't help.)
- n == board.length == board[i].length
- 2 ≤ n ≤ 20
- board[i][j] is -1 or in [1, n²]
- Squares 1 and n² have no snake or ladder
your turn
Try it before you peek
Read the examples, say the brute force out loud, then write code: here or on LeetCode ↗. Stuck for 20 minutes? Open one hint at a time.
Solve it in the browser
LeetCode-style: complete the class. Compiled by the real javac (Java 17) and judged right here — nothing is sent anywhere.
Solutions are hidden so you can try first. Even 20 minutes of real effort makes the answer stick far better than reading it.
Marking the problem solved, or opening every hint, also shows it.
the aha
Key insight
patternBFS shortest path (unweighted)
Squares are vertices; a roll is an edge to up to 6 squares (after taking any snake or ladder). Every roll costs 1, so the fewest rolls is a BFS from square 1. The only fiddly part is turning a square number into (row, col).
solutions
From brute force to optimal
Bellman–Ford style: keep a best-known roll count per square and keep improving it from every reachable square until a full pass changes nothing.
- dist[1] = 0, others ∞.
- Repeat: for every square with a finite dist, for each roll 1..6, follow any jump and lower dist[dest] if dist + 1 is smaller.
- Stop after a pass with no change; answer dist[n²] or -1.
Each pass is n² squares × 6 rolls, and it can take up to n² passes for values to settle.
One dist entry per square.
class Solution { /** Bellman-Ford style: keep improving dist[] with every possible roll until nothing changes. */ public int snakesAndLadders(int[][] board) { int n = board.length, last = n * n; int[] dist = new int[last + 1]; Arrays.fill(dist, Integer.MAX_VALUE); dist[1] = 0; boolean changed = true; while (changed) { // at most n² rounds: each round fixes at least one more square changed = false; for (int cur = 1; cur < last; cur++) { if (dist[cur] == Integer.MAX_VALUE) continue; for (int next = cur + 1; next <= Math.min(cur + 6, last); next++) { int[] rc = cell(next, n); int dest = board[rc[0]][rc[1]] == -1 ? next : board[rc[0]][rc[1]]; if (dist[cur] + 1 < dist[dest]) { dist[dest] = dist[cur] + 1; changed = true; } } } } return dist[last] == Integer.MAX_VALUE ? -1 : dist[last]; } private int[] cell(int label, int n) { int fromBottom = (label - 1) / n, offset = (label - 1) % n; int col = fromBottom % 2 == 0 ? offset : n - 1 - offset; return new int[] {n - 1 - fromBottom, col}; }}BFS from square 1. For each of the 6 rolls, convert the target square to (row, col), take its jump if any, and enqueue the destination if it is new.
- rolls[1] = 0; queue = [1].
- Poll cur; if cur == n², return rolls[cur].
- For next in cur+1..min(cur+6, n²): dest = board at next == -1 ? next : that value.
- If dest is unvisited: rolls[dest] = rolls[cur] + 1, enqueue it.
Each of the n² squares is enqueued at most once and tries 6 rolls.
The rolls array and the queue.
class Solution { /** Squares are vertices; one roll is one edge. BFS gives the fewest rolls. */ public int snakesAndLadders(int[][] board) { int n = board.length, last = n * n; int[] rolls = new int[last + 1]; // rolls needed to stand on each square; -1 = not reached Arrays.fill(rolls, -1); Deque<Integer> queue = new ArrayDeque<>(); rolls[1] = 0; queue.offer(1); while (!queue.isEmpty()) { int cur = queue.poll(); if (cur == last) return rolls[cur]; for (int next = cur + 1; next <= Math.min(cur + 6, last); next++) { int[] rc = cell(next, n); int dest = board[rc[0]][rc[1]] == -1 ? next : board[rc[0]][rc[1]]; // take at most one jump if (rolls[dest] != -1) continue; rolls[dest] = rolls[cur] + 1; queue.offer(dest); } } return -1; } /** Square label (1..n²) → {row, col}. Row 0 is the TOP; numbering starts bottom-left and zig-zags. */ private int[] cell(int label, int n) { int fromBottom = (label - 1) / n, offset = (label - 1) % n; int col = fromBottom % 2 == 0 ? offset : n - 1 - offset; // even rows from the bottom go left → right return new int[] {n - 1 - fromBottom, col}; }}in the room
How to say it in the interview
talk track
- Say: "Fewest rolls, every roll costs 1 → BFS over squares 1..n²."
- Write the label → (row, col) helper first and test it on a 2×2 and a 3×3 board out loud.
- Mark the destination after the jump as visited, not the square you rolled onto.
traps
- Getting the zig-zag wrong: row from the bottom = (s − 1) / n; on odd rows from the bottom the column runs right → left.
- Following a second jump when a ladder ends on another snake or ladder — only one jump per roll.
- Marking the rolled-onto square visited instead of the jump destination — you can block a square you never actually stand on.
what they ask next
Follow-ups
Return the actual sequence of rolls?
Store each square's parent when you first reach it, then walk back from n² to 1.
What if a die had k faces?
Same BFS with k edges per square: O(n² · k).
before you submit
Edge cases to test
- A ladder whose top starts another ladder — take only the first jump.
- Snakes cover every square you can roll to → -1.
- A ladder from square 2 straight to n² → 1 roll.
- A plain 20 × 20 board → ⌈399 / 6⌉ = 67 rolls.
practise next
Similar problems
- #127Word LadderHardin Graphs
- #1197Minimum Knight MovesMediumin GraphsLeetCode Premium
- #433Minimum Genetic MutationMediumin Graphs