← Назад к вопросам
Спиральный обход матрицы
1.0 Junior🔥 161 комментариев
#Python Core
Условие
Верните все элементы матрицы в порядке спирального обхода (по часовой стрелке, начиная с левого верхнего угла).
Пример
Вход:
[[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 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Спиральный обход матрицы
Это классическая задача на обход матрицы. Требует аккуратной работы с границами и логикой направлений.
1. Анализ проблемы
Спиральный обход — движение по внешнему слою матрицы, потом по внутренним слоям.
Матрица 3×3:
1 2 3
4 5 6
7 8 9
Порядок обхода:
→ → ↓ (строка 0: 1, 2, 3)
↓ (столбец 2: 6, 9)
← ← (строка 2: 8, 7)
↑ (столбец 0: 4)
↑ (центр: 5)
Результат: [1, 2, 3, 6, 9, 8, 7, 4, 5]
2. Решение 1: Четыре цикла направлений
def spiral_order(matrix: list[list[int]]) -> list[int]:
"""Спиральный обход с явными направлениями."""
if not matrix:
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
# Тестирование
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(spiral_order(matrix)) # [1, 2, 3, 6, 9, 8, 7, 4, 5]
Анализ:
- Время: O(m × n) — посещаем каждый элемент один раз
- Память: O(1) — не считая результата
Визуализация работы:
Матрица 3×3:
1 2 3 top=0, bottom=2, left=0, right=2
4 5 6
7 8 9
Шаг 1 (top <= bottom && left <= right):
Вправо (col 0→2, row 0): 1, 2, 3 top=1
Вниз (row 1→2, col 2): 6, 9 right=1
Влево (col 1→0, row 2): 8, 7 bottom=1
Вверх (row 1→1, col 0): 4 left=1
Шаг 2 (top <= bottom && left <= right):
top=1, bottom=1, left=1, right=1
Вправо (col 1→1, row 1): 5 top=2
Цикл завершен (top > bottom)
Результат: [1, 2, 3, 6, 9, 8, 7, 4, 5] ✓
3. Решение 2: Направления с дельтами
def spiral_order_directions(matrix: list[list[int]]) -> list[int]:
"""Спиральный обход с использованием направлений."""
if not matrix:
return []
m, n = len(matrix), len(matrix[0])
result = []
visited = [[False] * n for _ in range(m)]
# Направления: вправо, вниз, влево, вверх
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
direction_idx = 0
row, col = 0, 0
for _ in range(m * n):
result.append(matrix[row][col])
visited[row][col] = True
# Пытаемся продолжить в текущем направлении
dr, dc = directions[direction_idx]
next_row, next_col = row + dr, col + dc
# Если выходим за границы или уже посещали — меняем направление
if not (0 <= next_row < m and 0 <= next_col < n and not visited[next_row][next_col]):
direction_idx = (direction_idx + 1) % 4
dr, dc = directions[direction_idx]
next_row, next_col = row + dr, col + dc
row, col = next_row, next_col
return result
Преимущество: Более гибкий для других видов спирального обхода.
4. Полная реализация с тестами
from typing import List
import unittest
class Solution:
@staticmethod
def spiral_order(matrix: List[List[int]]) -> List[int]:
"""Оптимальное решение."""
if not matrix:
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
class TestSpiralOrder(unittest.TestCase):
def test_3x3_matrix(self):
"""Стандартный пример 3×3."""
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
expected = [1, 2, 3, 6, 9, 8, 7, 4, 5]
self.assertEqual(Solution.spiral_order(matrix), expected)
def test_1x1_matrix(self):
"""Матрица 1×1."""
matrix = [[1]]
expected = [1]
self.assertEqual(Solution.spiral_order(matrix), expected)
def test_1xn_matrix(self):
"""Матрица 1×n (одна строка)."""
matrix = [[1, 2, 3, 4]]
expected = [1, 2, 3, 4]
self.assertEqual(Solution.spiral_order(matrix), expected)
def test_mx1_matrix(self):
"""Матрица m×1 (один столбец)."""
matrix = [[1], [2], [3], [4]]
expected = [1, 2, 3, 4]
self.assertEqual(Solution.spiral_order(matrix), expected)
def test_2x2_matrix(self):
"""Матрица 2×2."""
matrix = [[1, 2], [3, 4]]
expected = [1, 2, 4, 3]
self.assertEqual(Solution.spiral_order(matrix), expected)
def test_4x4_matrix(self):
"""Матрица 4×4."""
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
]
expected = [1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10]
self.assertEqual(Solution.spiral_order(matrix), expected)
def test_3x4_matrix(self):
"""Матрица 3×4 (не квадратная)."""
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
]
expected = [1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7]
self.assertEqual(Solution.spiral_order(matrix), expected)
def test_empty_matrix(self):
"""Пустая матрица."""
matrix = []
expected = []
self.assertEqual(Solution.spiral_order(matrix), expected)
if __name__ == '__main__':
unittest.main()
5. Граничные случаи
Случай 1: Одна строка
[1, 2, 3, 4]
→ [1, 2, 3, 4]
Случай 2: Один столбец
[1]
[2]
[3]
[4]
↓ [1, 2, 3, 4]
Случай 3: Две строки и два столбца
[1, 2]
[3, 4]
→ ↓ [1, 2, 4, 3]
←
↑
Случай 4: Две строки и три столбца
[1, 2, 3]
[4, 5, 6]
→ → → [1, 2, 3, 6, 5, 4]
↓
← ←
6. Визуализация сложной матрицы 5×5
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
Спиральный порядок:
Внешний слой: 1, 2, 3, 4, 5, 10, 15, 20, 25, 24, 23, 22, 21, 16, 11, 6
Второй слой: 7, 8, 9, 14, 19, 18, 17, 12
Третий слой: 13
Результат: [1, 2, 3, 4, 5, 10, 15, 20, 25, 24, 23, 22, 21, 16, 11, 6, 7, 8, 9, 14, 19, 18, 17, 12, 13]
7. Обратное преобразование: расположение элемента в спирали
def spiral_position(m: int, n: int, target: int) -> tuple:
"""Найти позицию элемента в спиральном порядке."""
result = []
top, bottom = 0, m - 1
left, right = 0, n - 1
position = 0
while top <= bottom and left <= right:
for col in range(left, right + 1):
if position == target:
return (top, col)
position += 1
top += 1
for row in range(top, bottom + 1):
if position == target:
return (row, right)
position += 1
right -= 1
if top <= bottom:
for col in range(right, left - 1, -1):
if position == target:
return (bottom, col)
position += 1
bottom -= 1
if left <= right:
for row in range(bottom, top - 1, -1):
if position == target:
return (row, left)
position += 1
left += 1
return (-1, -1) # Не найдено
8. Сравнение подходов
| Подход | Времени | Память | Сложность | Гибкость |
|---|---|---|---|---|
| Четыре цикла | O(m×n) | O(1) | Средняя | Низкая |
| С направлениями | O(m×n) | O(m×n) | Высокая | Высокая |
9. Альтернативный обход — против часовой стрелки
def spiral_order_ccw(matrix: List[List[int]]) -> List[int]:
"""Спиральный обход против часовой стрелки."""
if not matrix:
return []
result = []
top, bottom = 0, len(matrix) - 1
left, right = 0, len(matrix[0]) - 1
while top <= bottom and left <= right:
# Вниз (левый столбец)
for row in range(top, bottom + 1):
result.append(matrix[row][left])
left += 1
# Вправо (нижняя строка)
for col in range(left, right + 1):
result.append(matrix[bottom][col])
bottom -= 1
# Вверх (правый столбец)
if left <= right:
for row in range(bottom, top - 1, -1):
result.append(matrix[row][right])
right -= 1
# Влево (верхняя строка)
if top <= bottom:
for col in range(right, left - 1, -1):
result.append(matrix[top][col])
top += 1
return result
Вывод
Для спирального обхода матрицы:
- Оптимальное решение: Четыре цикла с управлением границами
- Ключевой момент: Правильно обновлять границы (top, bottom, left, right)
- Граничные случаи: Одна строка, один столбец, не квадратные матрицы
- Проверки: Если условия перед влево и вверх циклами
- Применение: Обработка изображений, матричные операции
Частая задача на собеседованиях — проверяет аккуратность работы с индексами и логику алгоритма.