◀ THE GRIND — 2-D DYNAMIC PROGRAMMING

Unique Paths II

MEDIUM✓ CHIP-TIMEDLC #63 — FULL STATEMENT ↗

The drill: Same right/down grid walk as before, but some cells are boulders that block the route entirely. Count the paths from the top-left corner to the bottom-right that never step on one.

THE BRIEFING — THE FULL DRILL, IN MY OWN WORDS

The same right/down grid walk returns, except now some cells are marked as obstacles that block the route entirely — a route can never step onto one of those cells.

The runner still starts in the top-left corner and must reach the bottom-right corner using only right and down moves, and the count needed is how many distinct obstacle-free routes exist between those two corners.

If the starting cell or the ending cell itself is blocked, no route can exist at all, and the answer collapses to zero.

EX 01
obstacleGrid = [[0]]
1
SINGLE OPEN CELL
EX 02
obstacleGrid = [[1]]
0
SINGLE CELL, BLOCKED
EX 03
obstacleGrid = [[0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0]]
2
A TWO-WIDE WALL FORCES A DETOUR
THE HINTS — TAKE ONLY WHAT YOU NEED
HINT 1 THE NUDGE

The recursion is identical to the open grid — except a blocked cell contributes zero routes instead of one. Where does that zero need to propagate?

HINT 2 THE STRUCTURE

A blocked cell has no ways to be reached and nothing to pass forward — both directions collapse to zero, including if the blocker sits on the starting cell itself.

HINT 3 ONE STEP FROM THE ANSWER

Reuse the rolling-row DP: ways[c] += ways[c-1] normally, but slam ways[c] to 0 the instant an obstacle occupies that cell, before it can contribute to its neighbour.

COACH'S BOARD — THE PATTERN, STEP BY STEP
THE DETOUR COUNTPATTERN · GRID DP, OBSTACLES ZERO OUT3×4 grid · obstacles at (1,1) and (1,2)
1
STEP 1

Seed the entrance with one way to stand there, doing nothing.

STEP 1 / 6 · ← → WORK TOO
THE SPLITS — TWO PACES, TWO LANGUAGES
grind/unique-paths-ii.pyRACE PACE
LANG ▸
PACE ▸
class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
        m, n = len(obstacleGrid), len(obstacleGrid[0])
        row = [0] * n
        row[0] = 1
        for r in range(m):
            for c in range(n):
                if obstacleGrid[r][c] == 1:
                    row[c] = 0
                elif c > 0:
                    row[c] += row[c - 1]
        return row[-1]
TIME O(M·N)SPACE O(N)PYTHON · RACE PACE · 12 LN

✓ CHIP-TIMED — ALL 4 SOLUTIONS RAN GREEN AGAINST SELF-AUTHORED CASES IN CI · JDK 21 · CPYTHON 3.12 · NOTHING PUBLISHES RED