🧠
Simulation with Direction Vectors
💡 This approach uses direction vectors and a visited matrix to simulate the spiral traversal, which helps beginners understand direction changes and boundary conditions more explicitly.
Intuition
We move in one direction until we hit a boundary or visited cell, then turn right (change direction) and continue until all cells are visited.
Algorithm
- Initialize direction vectors for right, down, left, and up movements.
- Create a visited matrix to mark visited cells.
- Start from (0,0) and move in the current direction.
- If next cell is out of bounds or visited, turn right (change direction).
- Continue until all cells are visited.
💡 This approach explicitly models movement and direction changes, which can be easier to visualize but requires extra space for visited tracking.
from typing import List
def spiralOrder(matrix: List[List[int]]) -> List[int]:
if not matrix or not matrix[0]:
return []
m, n = len(matrix), len(matrix[0])
visited = [[False]*n for _ in range(m)]
result = []
directions = [(0,1),(1,0),(0,-1),(-1,0)] # right, down, left, up
dir_idx = 0
r = c = 0
for _ in range(m*n):
result.append(matrix[r][c])
visited[r][c] = True
dr, dc = directions[dir_idx]
nr, nc = r + dr, c + dc
if nr < 0 or nr >= m or nc < 0 or nc >= n or visited[nr][nc]:
dir_idx = (dir_idx + 1) % 4
dr, dc = directions[dir_idx]
nr, nc = r + dr, c + dc
r, c = nr, nc
return result
# Driver code
if __name__ == '__main__':
mat = [[1,2,3],[4,5,6],[7,8,9]]
print(spiralOrder(mat)) # Expected: [1,2,3,6,9,8,7,4,5]
Line Notes
visited = [[False]*n for _ in range(m)]Track which cells have been visited to avoid repeats
directions = [(0,1),(1,0),(0,-1),(-1,0)]Define movement vectors for right, down, left, up
dir_idx = 0Start moving right
for _ in range(m*n):Visit all cells exactly once
if nr < 0 or nr >= m or nc < 0 or nc >= n or visited[nr][nc]:Check if next cell is invalid or visited
dir_idx = (dir_idx + 1) % 4Turn right by cycling direction index
r, c = nr, ncMove to next valid cell
import java.util.*;
public class SpiralMatrix {
public static List<Integer> spiralOrder(int[][] matrix) {
List<Integer> result = new ArrayList<>();
if (matrix == null || matrix.length == 0) return result;
int m = matrix.length, n = matrix[0].length;
boolean[][] visited = new boolean[m][n];
int[][] directions = {{0,1},{1,0},{0,-1},{-1,0}};
int dirIdx = 0, r = 0, c = 0;
for (int i = 0; i < m * n; i++) {
result.add(matrix[r][c]);
visited[r][c] = true;
int nr = r + directions[dirIdx][0];
int nc = c + directions[dirIdx][1];
if (nr < 0 || nr >= m || nc < 0 || nc >= n || visited[nr][nc]) {
dirIdx = (dirIdx + 1) % 4;
nr = r + directions[dirIdx][0];
nc = c + directions[dirIdx][1];
}
r = nr;
c = nc;
}
return result;
}
public static void main(String[] args) {
int[][] mat = {{1,2,3},{4,5,6},{7,8,9}};
System.out.println(spiralOrder(mat)); // Expected: [1, 2, 3, 6, 9, 8, 7, 4, 5]
}
}
Line Notes
boolean[][] visited = new boolean[m][n];Track visited cells to prevent repeats
int[][] directions = {{0,1},{1,0},{0,-1},{-1,0}};Movement vectors for directions
int dirIdx = 0, r = 0, c = 0;Start at top-left moving right
for (int i = 0; i < m * n; i++)Visit all cells once
if (nr < 0 || nr >= m || nc < 0 || nc >= n || visited[nr][nc])Check boundary and visited conditions
dirIdx = (dirIdx + 1) % 4;Turn right when blocked
r = nr; c = nc;Move to next cell
#include <iostream>
#include <vector>
using namespace std;
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> result;
if (matrix.empty() || matrix[0].empty()) return result;
int m = matrix.size(), n = matrix[0].size();
vector<vector<bool>> visited(m, vector<bool>(n, false));
vector<pair<int,int>> directions = {{0,1},{1,0},{0,-1},{-1,0}};
int dirIdx = 0, r = 0, c = 0;
for (int i = 0; i < m * n; ++i) {
result.push_back(matrix[r][c]);
visited[r][c] = true;
int nr = r + directions[dirIdx].first;
int nc = c + directions[dirIdx].second;
if (nr < 0 || nr >= m || nc < 0 || nc >= n || visited[nr][nc]) {
dirIdx = (dirIdx + 1) % 4;
nr = r + directions[dirIdx].first;
nc = c + directions[dirIdx].second;
}
r = nr;
c = nc;
}
return result;
}
int main() {
vector<vector<int>> mat = {{1,2,3},{4,5,6},{7,8,9}};
vector<int> res = spiralOrder(mat);
for (int num : res) cout << num << " ";
cout << endl; // Expected: 1 2 3 6 9 8 7 4 5
return 0;
}
Line Notes
vector<vector<bool>> visited(m, vector<bool>(n, false));Keep track of visited cells
vector<pair<int,int>> directions = {{0,1},{1,0},{0,-1},{-1,0}};Direction vectors for movement
int dirIdx = 0, r = 0, c = 0;Start position and direction
for (int i = 0; i < m * n; ++i)Loop to visit all cells
if (nr < 0 || nr >= m || nc < 0 || nc >= n || visited[nr][nc])Check if next cell is invalid or visited
dirIdx = (dirIdx + 1) % 4;Change direction clockwise
r = nr; c = nc;Update current position
function spiralOrder(matrix) {
if (!matrix.length || !matrix[0].length) return [];
const m = matrix.length, n = matrix[0].length;
const visited = Array.from({length: m}, () => Array(n).fill(false));
const directions = [[0,1],[1,0],[0,-1],[-1,0]];
let dirIdx = 0, r = 0, c = 0;
const result = [];
for (let i = 0; i < m * n; i++) {
result.push(matrix[r][c]);
visited[r][c] = true;
let nr = r + directions[dirIdx][0];
let nc = c + directions[dirIdx][1];
if (nr < 0 || nr >= m || nc < 0 || nc >= n || visited[nr][nc]) {
dirIdx = (dirIdx + 1) % 4;
nr = r + directions[dirIdx][0];
nc = c + directions[dirIdx][1];
}
r = nr;
c = nc;
}
return result;
}
// Test
const mat = [[1,2,3],[4,5,6],[7,8,9]];
console.log(spiralOrder(mat)); // Expected: [1,2,3,6,9,8,7,4,5]
Line Notes
const visited = Array.from({length: m}, () => Array(n).fill(false));Create visited matrix to track cells
const directions = [[0,1],[1,0],[0,-1],[-1,0]];Define movement directions
let dirIdx = 0, r = 0, c = 0;Initialize starting position and direction
for (let i = 0; i < m * n; i++)Loop to visit all elements
if (nr < 0 || nr >= m || nc < 0 || nc >= n || visited[nr][nc])Check if next move is invalid or visited
dirIdx = (dirIdx + 1) % 4;Turn right when blocked
r = nr; c = nc;Update current position
We visit each element once, but use extra space for the visited matrix, increasing space complexity.
💡 For a 10x10 matrix, this means 100 operations plus 100 boolean flags stored.
Interview Verdict: Accepted
This approach is intuitive and accepted but uses extra space, which might be suboptimal for large inputs.