Clockwise Spiral Matrix Traversal That Turns at Blocked Cells
Company: Pinduoduo
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Given an `m x n` matrix of integers, return its values in clockwise spiral order: start at the top-left cell, go right along the top row, down the right column, left along the bottom row and up the left column, then keep circling inward until every cell has been output.
Follow-up: some cells are blockers. The walk never enters a blocker. When the next cell in the current direction is a blocker, the walk turns clockwise (to its right), just as it does at the edge of the matrix or in front of a cell it has already visited. Return the values in the order the walk visits them. A matrix with no blockers gives the plain spiral order, so one function answers both parts.
The report does not say when the blocker walk stops, or what happens when a single right turn is not enough; the rules below fix both.
### Function Signature
```python
def spiral_with_blockers(matrix: list[list[int]], blocked: list[list[int]]) -> list[int]:
```
`blocked` lists the blocker cells as `[row, col]` pairs.
### Rules
- Row `0` is the top row and column `0` is the leftmost column. Right leads from `(r, c)` to `(r, c + 1)`, down to `(r + 1, c)`, left to `(r, c - 1)` and up to `(r - 1, c)`. Turning clockwise goes from right to down, from down to left, from left to up, and from up to right.
- A cell is available if it lies inside the matrix, is not a blocker, and has not been visited yet.
- The walk starts on `(0, 0)` facing right. `(0, 0)` counts as visited, and its value is the first output.
- At each step, look at the next cell in the current direction. If it is available, move into it and output its value. If not, turn 90 degrees clockwise and look again, checking at most four directions in total. The first direction that leads to an available cell becomes the current direction, and the walk moves one cell in it.
- If none of the four directions leads to an available cell, the walk ends. Open cells it never reached are not output.
- Blockers are never output.
### Constraints
- `1 <= m, n <= 100`, where `m = len(matrix)` and `n = len(matrix[0])`; every row has length `n`.
- `-10^9 <= matrix[r][c] <= 10^9`
- `0 <= len(blocked) <= m * n - 1`
- Every pair in `blocked` lies inside the matrix, the pairs are distinct, and `[0, 0]` is never a blocker.
### Examples
**Example 1**
```text
Input: matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], blocked = []
Output: [1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7]
```
With no blockers this is the plain spiral: the outer ring, then `6` and `7` in the middle row.
**Example 2**
```text
Input: matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], blocked = [[1, 1]]
Output: [1, 2, 3, 4, 8, 12, 11, 10, 9, 5]
```
The walk matches Example 1 until it reaches `5` at `(1, 0)` facing up. From there, up leads to the visited `(0, 0)`, right to the blocker `(1, 1)`, down to the visited `(2, 0)`, and left out of the matrix, so the walk ends. The open cell holding `7` is never reached.
**Example 3**
```text
Input: matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], blocked = [[0, 1]]
Output: [1, 4, 7, 8, 9, 6, 3]
```
At `(0, 0)` the blocker on the right turns the walk down through `4` to `7`. At `(2, 0)` facing down, down and left are outside the matrix and up is visited, so after three clockwise turns the walk faces right and moves through `8` to `9`. At `(2, 2)` facing right, right and down are outside and left is visited, so it turns to face up and moves through `6` to `3`. At `(0, 2)` facing up, up and right are outside, down is visited and left is the blocker, so the walk ends without visiting `5`.
Overview: Return the values of a matrix in clockwise spiral order starting from the top-left cell, then extend the walk so that blocked cells force clockwise turns and can end it early. Tests precise grid simulation, direction rotation, visited and boundary checks, and an unambiguous stopping rule.
Read the full Pinduoduo Software Engineer interview experience this question came from
Given an `m x n` matrix of integers `matrix` and a list `blocked` of blocker cells given as `[row, col]` pairs, return the matrix values in the order a clockwise spiral walk visits them.
With no blockers this is the plain clockwise spiral order: start at the top-left cell, go right along the top row, down the right column, left along the bottom row and up the left column, then keep circling inward until every cell has been output. Blockers change the walk: it never enters a blocker, and when the next cell in the current direction is a blocker, the walk turns clockwise (to its right), just as it does at the edge of the matrix or in front of a cell it has already visited. One function answers both cases.
### Rules
- Row `0` is the top row and column `0` is the leftmost column. Right leads from `(r, c)` to `(r, c + 1)`, down to `(r + 1, c)`, left to `(r, c - 1)` and up to `(r - 1, c)`. Turning clockwise goes from right to down, from down to left, from left to up, and from up to right.
- A cell is *available* if it lies inside the matrix, is not a blocker, and has not been visited yet.
- The walk starts on `(0, 0)` facing right. `(0, 0)` counts as visited, and its value is the first output.
- At each step, look at the next cell in the current direction. If it is available, move into it and output its value. If not, turn 90 degrees clockwise and look again, checking at most four directions in total. The first direction that leads to an available cell becomes the current direction, and the walk moves one cell in it.
- If none of the four directions leads to an available cell, the walk ends. Open cells it never reached are not output.
- Blockers are never output.
Return the visited values as a list, in the order the walk visits them.
### Example 1
```text
Input: matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], blocked = [[1, 1]]
Output: [1, 2, 3, 4, 8, 12, 11, 10, 9, 5]
```
With `blocked = []` the answer would be the plain spiral `[1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7]`. With the blocker, the walk is the same until it reaches `5` at `(1, 0)` facing up. From there, up leads to the visited `(0, 0)`, right to the blocker `(1, 1)`, down to the visited `(2, 0)`, and left out of the matrix, so the walk ends. The open cell holding `7` is never reached.
### Example 2
```text
Input: matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], blocked = [[0, 1]]
Output: [1, 4, 7, 8, 9, 6, 3]
```
At `(0, 0)` the blocker on the right turns the walk down through `4` to `7`. At `(2, 0)` facing down, down and left are outside the matrix and up is visited, so after three clockwise turns the walk faces right and moves through `8` to `9`. At `(2, 2)` facing right, right and down are outside and left is visited, so it turns to face up and moves through `6` to `3`. At `(0, 2)` facing up, up and right are outside, down is visited and left is the blocker, so the walk ends without visiting `5`.
### Constraints
- `1 <= m, n <= 100`, where `m = len(matrix)` and `n = len(matrix[0])`; every row has length `n`.
- `-10^9 <= matrix[r][c] <= 10^9`
- `0 <= len(blocked) <= m * n - 1`
- Every pair in `blocked` lies inside the matrix, the pairs are distinct, and `[0, 0]` is never a blocker.
No value can exceed `2^31 - 1`: every matrix value and every output value fits in a signed 32-bit integer.
Constraints
- 1 <= m, n <= 100, where m = len(matrix) and n = len(matrix[0]); every row has length n
- -10^9 <= matrix[r][c] <= 10^9 (every value fits in a signed 32-bit integer)
- 0 <= len(blocked) <= m * n - 1
- Every pair in blocked lies inside the matrix, the pairs are distinct, and [0, 0] is never a blocker
Examples
Input: ([[7]], [])
Expected Output: [7]
Explanation: Minimum 1x1 matrix with no blockers returns its single value.
Input: ([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], [])
Expected Output: [1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7]
Explanation: Source Example 1: no blockers gives the plain spiral; the inner layer 6, 7 is a single row.
Hints
- The matrix edge, a blocker and an already visited cell all have the same effect on the walk: none of them can be entered next.
- Keep the current facing from one step to the next. A step may need more than one clockwise check before it moves, and the walk stops only after all four directions fail.
- The walk never jumps to a new region: open cells it cannot reach from its current position are simply left out of the answer.