Spiral Order of a Matrix With Blocker Cells That Force Clockwise Turns
Company: Temu
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
You are given an `m x n` matrix of integers. First, return all of its values in clockwise spiral order, from the outside in: start at the top-left cell, move right along the top row, down the right column, left along the bottom row, up the left column, and continue inward.
Follow-up: the matrix may contain blockers. The traversal never enters a blocker; when it runs into one, it turns clockwise (a right turn), the same way it turns at the matrix edge or at a cell it has already visited. Return the values in the order they are visited. Without blockers the result is the ordinary spiral order, so a single function covers both questions.
The report leaves open when the walk with blockers stops and what it does when one right turn is still blocked; the rules below settle both.
### Function Signature
```python
def spiral_with_blockers(matrix: list[list[int]], blocked: list[list[int]]) -> list[int]:
```
Each entry of `blocked` is a blocker cell given as `[row, col]`.
### Rules
- Row `0` is the top row and column `0` is the leftmost column. From `(r, c)`, right is `(r, c + 1)`, down is `(r + 1, c)`, left is `(r, c - 1)` and up is `(r - 1, c)`. A clockwise turn changes right to down, down to left, left to up, and up to right.
- A cell is available when it is inside the matrix, is not a blocker, and has not been visited.
- The walk begins on `(0, 0)` facing right; `(0, 0)` is visited first and its value is output first.
- On each step, check the next cell in the current direction. If it is available, move there and output its value. Otherwise turn clockwise by 90 degrees and check again, trying at most four directions in all. The first direction with an available next cell becomes the current direction, and the walk moves one cell that way.
- When no direction from the current cell leads to an available cell, the walk stops. Open cells that were never reached do not appear in the output.
- Blockers never appear in the output.
### Constraints
- `1 <= m, n <= 100`, where `m = len(matrix)` and `n = len(matrix[0])`; all rows have length `n`.
- `-10^9 <= matrix[r][c] <= 10^9`
- `0 <= len(blocked) <= m * n - 1`
- All blocker cells are inside the matrix and distinct, and `[0, 0]` is never a blocker.
### Examples
**Example 1**
```text
Input: matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], blocked = []
Output: [1, 2, 3, 6, 9, 8, 7, 4, 5]
```
The ordinary spiral: the outer ring clockwise, then the center.
**Example 2**
```text
Input: matrix = [[1, 2, 3], [4, 5, 6]], blocked = [[0, 1]]
Output: [1, 4, 5, 6, 3]
```
The blocker to the right of `(0, 0)` turns the walk down to `4`. At `(1, 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 `5` to `6`. At `(1, 2)` facing right, right and down are outside and left is visited, so it turns to face up and moves to `3`. At `(0, 2)` every direction is outside, visited or the blocker, so the walk stops.
**Example 3**
```text
Input: matrix = [[1, 2, 3, 4], [5, 6, 7, 8]], blocked = [[1, 3]]
Output: [1, 2, 3, 4]
```
At `(0, 3)` facing right, right is outside, down is the blocker, left is visited and up is outside, so the walk stops before reaching the bottom row.
Overview: Traverse an m x n matrix clockwise from the outside in, then handle a follow-up where some cells are blockers that the walk must turn away from. Tests careful simulation of direction changes, tracking of visited cells, and a precise rule for when the traversal stops.
Read the full Temu Software Engineer interview experience this question came from
You are given an `m x n` integer matrix `matrix` and a list `blocked` of blocker cells, each given as `[row, col]`. Return the values of `matrix` in the order a clockwise spiral walk visits them.
Without blockers the walk is the ordinary clockwise spiral, from the outside in: start at the top-left cell, move right along the top row, down the right column, left along the bottom row, up the left column, and continue inward. With blockers, the walk never enters a blocker; when it runs into one, it turns clockwise (a right turn), the same way it turns at the matrix edge or at a cell it has already visited.
### Rules
- Row `0` is the top row and column `0` is the leftmost column. From `(r, c)`, right is `(r, c + 1)`, down is `(r + 1, c)`, left is `(r, c - 1)` and up is `(r - 1, c)`. A clockwise turn changes right to down, down to left, left to up, and up to right.
- A cell is available when it is inside the matrix, is not a blocker, and has not been visited.
- The walk begins on `(0, 0)` facing right; `(0, 0)` is visited first and its value is output first.
- On each step, check the next cell in the current direction. If it is available, move there and output its value. Otherwise turn clockwise by 90 degrees and check again, trying at most four directions in all. The first direction with an available next cell becomes the current direction, and the walk moves one cell that way.
- When no direction from the current cell leads to an available cell, the walk stops. Open cells that were never reached do not appear in the output.
- Blockers never appear in the output.
Return the visited values as a list, in visiting order.
### Example 1
```text
Input: matrix = [[1, 2, 3], [4, 5, 6]], blocked = [[0, 1]]
Output: [1, 4, 5, 6, 3]
```
The blocker to the right of `(0, 0)` turns the walk down to `4`. At `(1, 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 `5` to `6`. At `(1, 2)` facing right, right and down are outside and left is visited, so it turns to face up and moves to `3`. At `(0, 2)` every direction is outside, visited or the blocker, so the walk stops.
### Example 2
```text
Input: matrix = [[1, 2, 3, 4], [5, 6, 7, 8]], blocked = [[1, 3]]
Output: [1, 2, 3, 4]
```
At `(0, 3)` facing right, right is outside, down is the blocker, left is visited and up is outside, so the walk stops before reaching the bottom row.
### Constraints
- `1 <= m, n <= 100`, where `m = len(matrix)` and `n = len(matrix[0])`; all rows have length `n`.
- `-10^9 <= matrix[r][c] <= 10^9`
- `0 <= len(blocked) <= m * n - 1`
- All blocker cells are inside the matrix and distinct, and `[0, 0]` is never a blocker.
No value can exceed `2^31 - 1` in magnitude, so 32-bit integers suffice; the output only copies matrix values.
Constraints
- 1 <= m, n <= 100, where m = len(matrix) and n = len(matrix[0]); all rows have length n
- -10^9 <= matrix[r][c] <= 10^9
- 0 <= len(blocked) <= m * n - 1
- All blocker cells are inside the matrix and distinct, and [0, 0] is never a blocker
Examples
Input: ([[7]], [])
Expected Output: [7]
Explanation: Minimum valid 1x1 matrix with no blockers returns its single value.
Input: ([[1, 2, 3], [4, 5, 6], [7, 8, 9]], [])
Expected Output: [1, 2, 3, 6, 9, 8, 7, 4, 5]
Explanation: Source Example 1: ordinary 3x3 spiral, the outer ring clockwise and then the center.
Hints
- Every move depends only on the current cell, the current direction and which neighbouring cells are still available, so the walk can be reproduced step by step.
- A blocker, a cell outside the matrix and an already visited cell all affect the walk in the same way.
- The walk ends the first time none of the four directions from the current cell leads to an available cell, even if some open cells remain.