Quick 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.

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

  1. 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.
  2. 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.
  3. The walk never jumps to a new region: open cells it cannot reach from its current position are simply left out of the answer.

Loading coding console...

Show the approach

Approach

Simulate the walk exactly as the rules define it. Keep an m x n grid of used flags and mark every blocker as used before the walk starts, so a cell outside the matrix, a blocker and an already visited cell are all rejected by one availability test. Directions are indexed 0..3 in the order right, down, left, up, so a clockwise turn is d = (d + 1) mod 4. Start on (0, 0) facing right, mark it and output matrix[0][0]. For each step, test the cell ahead; if it is not available, turn clockwise and test again, at most four times in total. The first available cell is entered, marked and output, and the direction that reached it stays the current direction for the next step. If all four tests fail, the walk ends.

Invariant: after every step the output holds exactly the visited open cells in visit order, the used grid marks exactly the blockers plus those cells, and d is the direction of the last move. Correctness: each step performs the same checks in the same order as the rules, so the produced sequence is the defined walk; blockers are pre-marked and therefore never entered or output, and cells the walk never reaches are never output. Termination: every move marks a new open cell, so there are at most m * n - len(blocked) moves, each with at most four tests.

Edge cases: a 1 x 1 matrix, or a start whose right and down neighbours are both blockers, returns only matrix[0][0]; a single row or column ends at its far edge or at the first blocker on it; the walk may end early and leave open cells unreached. Values are copied unchanged, so 32-bit integers suffice in every language.

Time complexity:
O(m * n)
Space complexity:
O(m * n)