Problem Overview
LeetCode 885 Spiral Matrix III gives you an R x C grid and a starting cell (rStart, cStart). Your task is to walk outward in a clockwise spiral from that starting point and return an array of all grid coordinates in the order they are visited. Every cell in the grid must appear in the result exactly once.
Unlike Spiral Matrix I and II, the grid here is not pre-filled with values — you are not reading a matrix or filling one. Instead you are purely generating the sequence of coordinates produced by a spiral walk that starts anywhere, including near or at an edge, and expands until it has covered the entire R x C region.
The challenge is handling the out-of-bounds positions that the spiral naturally produces when it walks off the edge of the grid. The spiral must continue undisturbed — positions outside [0,R) x [0,C) are simply skipped, but the walk itself never pauses or resets.
- Given R x C grid and starting cell (rStart, cStart)
- Walk in a clockwise spiral collecting all valid grid positions
- Return cells in the order they are visited
- Out-of-bounds positions during the spiral walk are skipped, not collected
Spiral Walk Pattern
The spiral proceeds in four directions in a fixed clockwise cycle: right (0,+1), down (+1,0), left (0,-1), up (-1,0). You move some number of steps in each direction before turning. The number of steps you take per direction is what makes this an expanding spiral rather than a circle.
The step count starts at 1 and increases by 1 after every two direction changes. So you go right 1, down 1, then step count becomes 2: left 2, up 2, then step count becomes 3: right 3, down 3, and so on. This doubling-every-two-turns rule is the mathematical heart of the algorithm.
Because the step count grows by 1 every two directions, the spiral expands evenly in all directions. After completing a full cycle of four directions with step count k, the frontier has moved k cells further out on each side, which is why the pattern covers the entire grid regardless of where it starts.
Step Pattern: Increase Every Two Turns
The step pattern is: go right 1, down 1, left 2, up 2, right 3, down 3, left 4, up 4... Steps increase by 1 after every TWO turns, not every turn. A common mistake is incrementing after each direction change, which makes the spiral too tight and leaves cells unvisited.
Algorithm
Define the direction array as dirs = [(0,1),(1,0),(0,-1),(-1,0)] for right, down, left, up. Initialize steps=1, dirIndex=0, result=[]. Start at (r,c) = (rStart, cStart). The outer loop continues until result contains R*C entries.
In each iteration of the outer loop, take steps in the current direction. For each position along that direction, check if the cell is within bounds [0,R) x [0,C). If it is, append it to result. After completing steps in one direction, advance dirIndex modulo 4 to turn. After every two turns, increment steps by 1.
The loop terminates once result.length == R*C. At that point every grid cell has been visited exactly once and the result is returned. The outer loop never needs a termination condition based on direction count — only the collected cell count matters.
- 1dirs = [(0,1),(1,0),(0,-1),(-1,0)]
- 2steps = 1, dirIndex = 0, result = [], r = rStart, c = cStart
- 3Append (r,c) to result if in bounds [0,R) x [0,C)
- 4While len(result) < R*C:
- 5 For each of 2 directions with current step count:
- 6 Walk steps positions in dirs[dirIndex % 4]
- 7 For each position: if in bounds, append to result
- 8 dirIndex += 1
- 9 steps += 1
- 10Return result
Handling Out-of-Bounds
When the spiral walk extends beyond the grid boundaries, those positions are simply skipped. The walk continues in the same direction for the full allotted step count — no direction change or step reset occurs just because a position is out of bounds. The spiral geometry is driven entirely by the step counter, not by the grid edges.
This means the spiral can walk off the edge, re-enter the grid, walk off again, and re-enter multiple times during a single direction segment. Each time it re-enters, the in-bounds cells are added to the result. Out-of-bounds cells are tested and discarded without affecting the step or direction counters.
The total number of positions visited (including out-of-bounds) can be much larger than R*C. But the result array only grows when a valid cell is found, and the algorithm stops as soon as result reaches R*C. The extra work from out-of-bounds steps is bounded and does not affect correctness.
Out-of-Bounds Steps Are Bounded
You visit positions outside the grid but do not record them. Total steps can be up to O((max(R,C))^2) because the spiral may need to walk a large perimeter around the grid before re-entering, but valid cells collected are exactly R*C. The wasted steps are bounded — the spiral always returns to cover the full grid.
Walk-Through Example
Consider a 1x4 grid (R=1, C=4) starting at (rStart=0, cStart=0). We need to collect 4 cells. The spiral begins at (0,0) — valid, add it. steps=1, dirIndex=0.
Direction 0 (right, steps=1): move to (0,1) — valid, add. dirIndex=1. Direction 1 (down, steps=1): move to (1,1) — row 1 is out of bounds, skip. dirIndex=2. steps becomes 2. Direction 2 (left, steps=2): move to (0,0) — already collected but still valid, skip since we track by count not visited set... actually the spiral revisits are fine since result fills to R*C and stops.
Continuing: Direction 2 left step 2: (0,-1) — out of bounds skip. dirIndex=3. Direction 3 (up, steps=2): (-1,0) and (-2,0) — both out of bounds. dirIndex=4 → 0. steps=3. Direction 0 (right, steps=3): (0,1) skip (already in result), (0,2) valid add, (0,3) valid add. Result now has 4 cells — done.
- 1Start (0,0): collect → result=[(0,0)]
- 2Right 1: (0,1) valid → result=[(0,0),(0,1)]
- 3Down 1: (1,1) out of bounds → skip
- 4steps → 2
- 5Left 2: (0,0) already counted, (0,-1) OOB → skip both
- 6Up 2: (-1,-1), (-2,-1) both OOB → skip
- 7steps → 3
- 8Right 3: (0,2) valid, (0,3) valid → result has all 4 cells → done
Code Walkthrough — Python and Java
Python solution: def spiralMatrixIII(R, C, rStart, cStart): dirs=[(0,1),(1,0),(0,-1),(-1,0)]; res=[]; steps=1; d=0; r,c=rStart,cStart; res.append([r,c]); while len(res)<R*C: for _ in range(2): dr,dc=dirs[d%4]; for _ in range(steps): r+=dr; c+=dc; if 0<=r<R and 0<=c<C: res.append([r,c]); d+=1; steps+=1; return res. The direction array, step counter, and inner double-loop handle the two-direction-per-step-increment rule cleanly.
Java solution: int[][] dirs={{0,1},{1,0},{0,-1},{-1,0}}; int[][] res=new int[R*C][2]; int idx=0,steps=1,d=0,r=rStart,c=cStart; res[idx++]=new int[]{r,c}; while(idx<R*C){for(int t=0;t<2;t++){int dr=dirs[d%4][0],dc=dirs[d%4][1]; for(int s=0;s<steps;s++){r+=dr;c+=dc;if(r>=0&&r<R&&c>=0&&c<C)res[idx++]=new int[]{r,c};} d++;} steps++;} return res. Time complexity is O(max(R,C)^2) and space is O(R*C) for the output.
Both solutions use the same structural pattern: an outer loop over step increments, an inner loop over two direction segments per increment, and the innermost loop walking step positions per direction. The bounds check is the only grid-specific logic — the rest is pure spiral geometry.
Increment Steps After Every 2 Directions, Not Every 1
Increment step count after every 2 direction changes, not every 1. Incrementing every turn makes the spiral too tight — it turns too sharply and misses cells on the outer rings. The correct pattern groups directions in pairs (right+down, left+up) and increments steps once per pair. This is the single most common bug in spiral walk implementations.