← Назад к вопросам
Спиральный обход матрицы
2.3 Middle🔥 181 комментариев
#Теория тестирования
Условие
Дана матрица M x N. Верните все элементы матрицы в спиральном порядке.
Пример
Вход: [[1,2,3],[4,5,6],[7,8,9]] Выход: [1,2,3,6,9,8,7,4,5]
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение: Спиральный обход матрицы
Это задача требует обхода матрицы по спирали: слева направо, сверху вниз, справа налево, снизу вверх, и повторения этого процесса для внутренних слоёв матрицы. Используем подход с четырьмя указателями границ.
Алгоритм решения
- Инициализируем четыре указателя для границ матрицы: top, bottom, left, right
- Проходим спирально:
- Слева направо по верхней строке (top)
- Сверху вниз по правому столбцу (right)
- Справа налево по нижней строке (bottom), если есть оставшиеся строки
- Снизу вверх по левому столбцу (left), если есть оставшиеся столбцы
- Сужаем границы после каждого прохода
- Повторяем пока не обойдём всю матрицу
Визуализация
Матрица 3x3:
1 2 3
4 5 6
7 8 9
Шаг 1 - Слева направо по top: 1, 2, 3 (top--)
Шаг 2 - Сверху вниз по right: 6, 9 (right--)
Шаг 3 - Справа налево по bottom: 8, 7 (bottom--)
Шаг 4 - Снизу вверх по left: 4, 5 (left++)
Результат: [1, 2, 3, 6, 9, 8, 7, 4, 5]
Реализация решения
def spiralOrder(matrix):
"""
Возвращает элементы матрицы в спиральном порядке.
Args:
matrix: Матрица M x N
Returns:
Список элементов в спиральном порядке
"""
if not matrix or not matrix[0]:
return []
result = []
top, bottom = 0, len(matrix) - 1
left, right = 0, len(matrix[0]) - 1
while top <= bottom and left <= right:
# Слева направо по верхней строке
for col in range(left, right + 1):
result.append(matrix[top][col])
top += 1
# Сверху вниз по правому столбцу
for row in range(top, bottom + 1):
result.append(matrix[row][right])
right -= 1
# Справа налево по нижней строке (если есть)
if top <= bottom:
for col in range(right, left - 1, -1):
result.append(matrix[bottom][col])
bottom -= 1
# Снизу вверх по левому столбцу (если есть)
if left <= right:
for row in range(bottom, top - 1, -1):
result.append(matrix[row][left])
left += 1
return result
Пошаговый разбор примера
Вход: [[1,2,3],[4,5,6],[7,8,9]]
Инициализация:
top = 0, bottom = 2, left = 0, right = 2
Итерация 1:
Шаг 1 (слева направо, top=0): 1, 2, 3 (top=1)
Шаг 2 (сверху вниз, right=2): 6, 9 (right=1)
Шаг 3 (справа налево, bottom=2): 8, 7 (bottom=1)
Шаг 4 (снизу вверх, left=0): 4, 5 (left=1)
Итерация 2:
top=1, bottom=1, left=1, right=1
Средний элемент 5 уже обойдён
top > bottom → выход
Выход: [1, 2, 3, 6, 9, 8, 7, 4, 5] ✓
Обработка граничных случаев
def spiralOrder_safe(matrix):
"""
Версия с обработкой граничных случаев
"""
# Проверка на пустую матрицу
if not matrix:
return []
if not matrix[0]:
return []
m, n = len(matrix), len(matrix[0])
result = []
top, bottom, left, right = 0, m - 1, 0, n - 1
while top <= bottom and left <= right:
# Проход слева направо
for j in range(left, right + 1):
result.append(matrix[top][j])
top += 1
# Проход сверху вниз
for i in range(top, bottom + 1):
result.append(matrix[i][right])
right -= 1
# Проход справа налево (только если есть строки)
if top <= bottom:
for j in range(right, left - 1, -1):
result.append(matrix[bottom][j])
bottom -= 1
# Проход снизу вверх (только если есть столбцы)
if left <= right:
for i in range(bottom, top - 1, -1):
result.append(matrix[i][left])
left += 1
return result
Тестовые случаи
# Основной пример
print(spiralOrder([[1,2,3],[4,5,6],[7,8,9]]))
# [1, 2, 3, 6, 9, 8, 7, 4, 5]
# Матрица 1x4 (одна строка)
print(spiralOrder([[1,2,3,4]]))
# [1, 2, 3, 4]
# Матрица 4x1 (один столбец)
print(spiralOrder([[1],[2],[3],[4]]))
# [1, 2, 3, 4]
# Матрица 1x1
print(spiralOrder([[5]]))
# [5]
# Матрица 2x2
print(spiralOrder([[1,2],[3,4]]))
# [1, 2, 4, 3]
# Матрица 2x3
print(spiralOrder([[1,2,3],[4,5,6]]))
# [1, 2, 3, 6, 5, 4]
# Матрица 3x2
print(spiralOrder([[1,2],[3,4],[5,6]]))
# [1, 2, 4, 6, 5, 3]
# Пустая матрица
print(spiralOrder([]))
# []
# Матрица с пустыми строками
print(spiralOrder([[], []]))
# []
Альтернативное решение с использованием поворота
def spiralOrder_rotate(matrix):
"""
Рекурсивное решение с поворотом матрицы
"""
if not matrix or not matrix[0]:
return []
# Первая строка + спираль оставшейся матрицы (повёрнутой)
result = matrix[0]
if len(matrix) > 1:
# Проворачиваем оставшуюся матрицу на 90 градусов
remaining = [[matrix[i][j] for i in range(len(matrix) - 1, 0, -1)]
for j in range(1, len(matrix[0]))]
result += spiralOrder_rotate(remaining)
return result
Сложность
- Временная сложность: O(m * n), где m и n — размеры матрицы (посещаем каждый элемент один раз)
- Пространственная сложность: O(1), не считая выходного массива (используем только указатели)
Визуализация разных размеров матриц
Матрица 2x3:
1 2 3
4 5 6
Обход: 1 → 2 → 3 → 6 → 5 → 4
Матрица 4x4:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
Обход: 1→2→3→4→8→12→16→15→14→13→9→5→6→7→11→10
Важные детали
- Проверка границ перед горизонтальными проходами справа налево и вертикальными проходами снизу вверх
- Уменьшение границ происходит после каждого прохода
- Граничные случаи включают матрицы из одной строки, одного столбца или одного элемента
Решение оптимально по времени и подходит для production-кода. Двухмерный обход требует внимательности, но алгоритм интуитивен после понимания основной идеи.