Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
Given an m x n matrix, return all elements of the matrix in spiral order.
Example 1:
Input: matrix = [[1,2,3],[4,5,6],[7,8,9]] Output: [1,2,3,6,9,8,7,4,5]
Example 2:
Input: matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]] Output: [1,2,3,4,8,12,11,10,9,5,6,7]
Constraints:
m == matrix.lengthn == matrix[i].length1 <= m, n <= 10-100 <= matrix[i][j] <= 100Problem summary: Given an m x n matrix, return all elements of the matrix in spiral order. Example 1: Input: matrix = [[1,2,3],[4,5,6],[7,8,9]] Output: [1,2,3,6,9,8,7,4,5] Example 2: Input: matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]] Output: [1,2,3,4,8,12,11,10,9,5,6,7]
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array
[[1,2,3],[4,5,6],[7,8,9]]
[[1,2,3,4],[5,6,7,8],[9,10,11,12]]
spiral-matrix-ii)spiral-matrix-iii)spiral-matrix-iv)import java.util.*;
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> ans = new ArrayList<>();
if (matrix.length == 0) return ans;
int top = 0, bottom = matrix.length - 1;
int left = 0, right = matrix[0].length - 1;
while (top <= bottom && left <= right) {
for (int c = left; c <= right; c++) ans.add(matrix[top][c]);
top++;
for (int r = top; r <= bottom; r++) ans.add(matrix[r][right]);
right--;
if (top <= bottom) {
for (int c = right; c >= left; c--) ans.add(matrix[bottom][c]);
bottom--;
}
if (left <= right) {
for (int r = bottom; r >= top; r--) ans.add(matrix[r][left]);
left++;
}
}
return ans;
}
}
func spiralOrder(matrix [][]int) []int {
if len(matrix) == 0 {
return []int{}
}
top, bottom := 0, len(matrix)-1
left, right := 0, len(matrix[0])-1
ans := []int{}
for top <= bottom && left <= right {
for c := left; c <= right; c++ {
ans = append(ans, matrix[top][c])
}
top++
for r := top; r <= bottom; r++ {
ans = append(ans, matrix[r][right])
}
right--
if top <= bottom {
for c := right; c >= left; c-- {
ans = append(ans, matrix[bottom][c])
}
bottom--
}
if left <= right {
for r := bottom; r >= top; r-- {
ans = append(ans, matrix[r][left])
}
left++
}
}
return ans
}
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
if not matrix:
return []
top, bottom = 0, len(matrix) - 1
left, right = 0, len(matrix[0]) - 1
ans: List[int] = []
while top <= bottom and left <= right:
for c in range(left, right + 1):
ans.append(matrix[top][c])
top += 1
for r in range(top, bottom + 1):
ans.append(matrix[r][right])
right -= 1
if top <= bottom:
for c in range(right, left - 1, -1):
ans.append(matrix[bottom][c])
bottom -= 1
if left <= right:
for r in range(bottom, top - 1, -1):
ans.append(matrix[r][left])
left += 1
return ans
impl Solution {
pub fn spiral_order(matrix: Vec<Vec<i32>>) -> Vec<i32> {
if matrix.is_empty() {
return vec![];
}
let mut top: i32 = 0;
let mut bottom: i32 = matrix.len() as i32 - 1;
let mut left: i32 = 0;
let mut right: i32 = matrix[0].len() as i32 - 1;
let mut ans = Vec::new();
while top <= bottom && left <= right {
for c in left..=right {
ans.push(matrix[top as usize][c as usize]);
}
top += 1;
for r in top..=bottom {
ans.push(matrix[r as usize][right as usize]);
}
right -= 1;
if top <= bottom {
for c in (left..=right).rev() {
ans.push(matrix[bottom as usize][c as usize]);
}
bottom -= 1;
}
if left <= right {
for r in (top..=bottom).rev() {
ans.push(matrix[r as usize][left as usize]);
}
left += 1;
}
}
ans
}
}
function spiralOrder(matrix: number[][]): number[] {
if (matrix.length === 0) return [];
let top = 0;
let bottom = matrix.length - 1;
let left = 0;
let right = matrix[0].length - 1;
const ans: number[] = [];
while (top <= bottom && left <= right) {
for (let c = left; c <= right; c++) ans.push(matrix[top][c]);
top++;
for (let r = top; r <= bottom; r++) ans.push(matrix[r][right]);
right--;
if (top <= bottom) {
for (let c = right; c >= left; c--) ans.push(matrix[bottom][c]);
bottom--;
}
if (left <= right) {
for (let r = bottom; r >= top; r--) ans.push(matrix[r][left]);
left++;
}
}
return ans;
}
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.