Editorial solutions and visualizations are prepared with care, but we do not guarantee 100% accuracy or completeness. Please use your own judgment to verify results. Visucodize is not responsible for decisions made based on this content.
Solution code
constPROCESSED='processed',PROCESSED_COLOR='blue';functionvisMainFunction(inputMatrix){if(inputMatrix.length ===0|| inputMatrix[0].length ===0){notification(`❌ <b>Invalid input:</b> The matrix is empty.`);return;}initClassProperties();explanationAndColorSchemaNotifications();startBatch();const matrix =newVisArray2D(...(inputMatrix.map(row=>newVisArray(...row))));let top =0, bottom = matrix.length -1;let left =0, right = matrix[0].length -1;let result =newVisArray();makeVisVariable(top).options({label:'top'}).createVis();makeVisVariable(bottom).options({label:'bottom'}).createVis();makeVisVariable(left).options({label:'left'}).createVis();makeVisVariable(right).options({label:'right'}).createVis();endBatch();notification(`
✅ <b>Initialization complete.</b><br>
We maintain four boundaries that define the current layer of the matrix:
<ul>
<li><b>Top:</b> Index of the first row that has not yet been fully traversed.</li>
<li><b>Bottom:</b> Index of the last row that has not yet been fully traversed.</li>
<li><b>Left:</b> Index of the first column that has not yet been fully traversed.</li>
<li><b>Right:</b> Index of the last column that has not yet been fully traversed.</li>
</ul>
We now begin the main loop, which continues while
<code>top ≤ bottom</code> <b>and</b> <code>left ≤ right</code> —
meaning there are still unprocessed cells remaining within the current boundaries.
`);while(top <= bottom && left <= right){startPartialBatch();notification(`🔄 <b>Spiral Traversal Step:</b> <br/>
<b>Current Boundaries</b> → Top = <b>${top}</b>, Bottom = <b>${bottom}</b>, Left = <b>${left}</b>, Right = <b>${right}</b>.`);// Traverse from left to rightnotification(`▶️ Starting <b>Left → Right</b> along top row <b>${top}</b> from column <b>${left}</b> to <b>${right}</b>.`);for(let col = left; col <= right; col++){highlightCell(matrix, top, col);
result.push(matrix[top][col]);notification(`➡️ Moving <b>Right</b>: Added <b>matrix[${makeColoredSpan(top,PROCESSED_COLOR)}][${makeColoredSpan(col,PROCESSED_COLOR)}] = ${makeColoredSpan(matrix[top][col],PROCESSED_COLOR)}</b> to the output.`);}notification(`✅ <b>Completed processing row ${top}</b>. All columns in this row have been visited, so we <b>increment top to ${top +1}</b> to exclude it from future traversals.`);
top +=1;// Traverse from top to bottomnotification(`▶️ Starting <b>Top → Bottom</b> down rightmost column <b>${right}</b> from row <b>${top}</b> to <b>${bottom}</b>.`);for(let row = top; row <= bottom; row++){highlightCell(matrix, row, right);
result.push(matrix[row][right]);notification(`⬇️ Moving <b>Down</b>: Added <b>matrix[${makeColoredSpan(row,PROCESSED_COLOR)}][${makeColoredSpan(right,PROCESSED_COLOR)}] = ${makeColoredSpan(matrix[row][right],PROCESSED_COLOR)}</b> to the output.`);}notification(`✅ <b>Completed processing column ${right}</b>. Since we have visited all rows in this column, we <b>decrement right to ${right -1}</b> to exclude it from future traversals.`);
right -=1;// Traverse from right to left (only if there are remaining rows)if(top <= bottom){notification(`▶️ Starting <b>Right → Left</b> along bottom row <b>${bottom}</b> from column <b>${right}</b> to <b>${left}</b>.`);for(let col = right; col >= left; col--){highlightCell(matrix, bottom, col);
result.push(matrix[bottom][col]);notification(`⬅️ Moving <b>Left</b>: Added <b>matrix[${makeColoredSpan(bottom,PROCESSED_COLOR)}][${makeColoredSpan(col,PROCESSED_COLOR)}] = ${makeColoredSpan(matrix[bottom][col],PROCESSED_COLOR)}</b> to the output.`);}notification(`✅ <b>Completed processing row ${bottom}</b>. Since we have visited all columns in this row, we <b>decrement bottom to ${bottom -1}</b> to exclude it from future traversals.`);
bottom -=1;}else{notification(`⚠️ <b>Skipping leftward traversal</b>: The <b>top boundary (${top})</b> has already exceeded the bottom boundary <b>(${bottom})</b>, meaning all rows are processed.`);}// Traverse from bottom to top (only if there are remaining columns)if(left <= right){notification(`▶️ Starting <b>Bottom → Top</b> up leftmost column <b>${left}</b> from row <b>${bottom}</b> to <b>${top}</b>.`);for(let row = bottom; row >= top; row--){highlightCell(matrix, row, left);
result.push(matrix[row][left]);notification(`⬆️ Moving <b>Up</b>: Added <b>matrix[${makeColoredSpan(row,PROCESSED_COLOR)}][${makeColoredSpan(left,PROCESSED_COLOR)}] = ${makeColoredSpan(matrix[row][left],PROCESSED_COLOR)}</b> to the output.`);}notification(`✅ <b>Completed processing column ${left}</b>. Since we have visited all rows in this column, we <b>increment left to ${left +1}</b> to exclude it from future traversals.`);
left +=1;}else{notification(`⚠️ <b>Skipping upward traversal</b>: The <b>left boundary (${left})</b> has already exceeded the right boundary <b>(${right})</b>, meaning all columns are processed.`);}endBatch();}notification(`🏁 <b>Finished!</b> The matrix has been traversed in spiral order.<br>
<b>Final Output:</b> [${result.join(', ')}]`);return result;}functionhighlightCell(matrix, row, col){
matrix.makeVisManagerForIndexPair(row, col).addClass(PROCESSED);}functionexplanationAndColorSchemaNotifications(){explanationNotification();notification(`
🎨 <b>Color legend</b>
<ul>
<li>Cells with a <b>${makeColoredSpan(PROCESSED_COLOR+' background',PROCESSED_COLOR)}</b> are <b>processed</b> (visited and appended to the output).</li>
</ul>
`);}functioninitClassProperties(){setClassProperties(PROCESSED,{backgroundColor:PROCESSED_COLOR});}
Solution explanation
Solution explanation
Approach
The matrix is traversed layer by layer in a spiral pattern using four boundaries:
top, bottom, left, and right.
Each boundary represents the outermost row or column that has not yet been completely processed.
As elements along one boundary are visited, that boundary moves inward to exclude the completed layer.
Boundary definitions:
Top: Index of the first row that has not yet been fully traversed.
Bottom: Index of the last row that has not yet been fully traversed.
Left: Index of the first column that has not yet been fully traversed.
Right: Index of the last column that has not yet been fully traversed.
Initialization:
Set top = 0, bottom = m − 1, left = 0, and right = n − 1,
where m and n are the number of rows and columns respectively.
Main Loop:
Continue while both top ≤ bottom and left ≤ right hold — meaning there are still unprocessed cells within the current boundary region.
Left → Right: Traverse the topmost remaining row, then increment top to exclude it.
Top → Bottom: Traverse the rightmost remaining column, then decrement right to exclude it.
Right → Left: Traverse the bottom row only if top ≤ bottom still holds —
meaning there are still unprocessed rows after moving the top boundary upward.
Then decrement bottom to exclude that row.
Bottom → Top: Traverse the leftmost column only if left ≤ right still holds —
meaning there are still unprocessed columns after moving the right boundary leftward.
Then increment left to exclude that column.
Why the boundary checks matter:
After each directional traversal, the corresponding boundary moves inward.
The conditions top ≤ bottom and left ≤ right ensure that we do not revisit
any already-processed rows or columns. Once a boundary crosses its opposite, it means all cells in that
dimension have been fully covered.
Result:
When the loop finishes, all elements have been collected in spiral order and stored in the output list.
Time Complexity
Each cell is visited exactly once, so the running time is O(m × n),
where m is the number of rows and n is the number of columns in the matrix.
Space Complexity
Auxiliary space is O(1). If you include the output array, total space is O(m × n)
Input-1
Input-2
Visucodize editorial solution titled JS Solution for LeetCode's Spiral Matrix coding problem. Includes code and may include explanation. You can animate the code step by step using the provided input by clicking the run button, or fork it locally to update the code and input for custom visualization. View the original problem at https://leetcode.com/problems/spiral-matrix.