Data structures problem 29 of 30

Shortest path in a grid

  • Data structures
  • Hard

A maze is given as a list of strings, where "." is open and "#" is a wall. Moving up, down, left or right, write shortest_path(grid) that returns the fewest steps from the top-left corner to the bottom-right corner, or -1 if there is no way through.

grid = [
    "..#.",
    ".##.",
    "....",
]
shortest_path(grid)   # 5
Show hint

Breadth-first search explores every cell 1 step away, then every cell 2 steps away, and so on. The first time it reaches the goal is the shortest route.

Show solution
from collections import deque

def shortest_path(grid):
    rows, cols = len(grid), len(grid[0])
    if grid[0][0] == "#" or grid[-1][-1] == "#":
        return -1
    dist = {(0, 0): 0}
    queue = deque([(0, 0)])
    while queue:
        r, c = queue.popleft()
        if (r, c) == (rows - 1, cols - 1):
            return dist[(r, c)]
        for nr, nc in ((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)):
            if 0 <= nr < rows and 0 <= nc < cols:
                if grid[nr][nc] == "." and (nr, nc) not in dist:
                    dist[(nr, nc)] = dist[(r, c)] + 1
                    queue.append((nr, nc))
    return -1

BFS finds shortest paths whenever every step costs the same. The dist dictionary doubles as the "visited" set, so each cell is queued once: O(rows × cols). Depth-first search would find a path, but not necessarily the shortest. When steps have different costs, you need Dijkstra's algorithm instead.

Want a problem like this every day? See today's problem and keep a streak going.