Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. BFS: Основы
bfs_basics

BFS: Основы

Level Order, Right Side View, Min Depth.

BFS: Основы и обход дерева

Поиск в ширину — обход графа уровнями. Использует очередь. Находит кратчайший путь в невзвешенном графе.

#1. Суть паттерна

BFS обходит граф/дерево уровнями: сначала все узлы на расстоянии 1, затем на расстоянии 2, и т.д.

#1.1 Термины

Граф — структура из вершин (узлов) и рёбер (соединений между вершинами).

Очередь (Queue) — структура данных FIFO (First-In-First-Out).

Уровень — все узлы на одинаковом расстоянии от начального.

Кратчайший путь — путь с минимальным количеством рёбер.

#Когда применять

  • ✅ Кратчайший путь — в невзвешенном графе
  • ✅ Уровневый обход — дерева, сетки
  • ✅ Минимальное количество шагов — лабиринты, слова
  • ✅ Поиск ближайших соседей

#Шаблон

from collections import deque def bfs(start): queue = deque([start]) visited = {start} steps = 0 while queue: # Обрабатываем весь уровень for _ in range(len(queue)): node = queue.popleft() if is_target(node): return steps for neighbor in get_neighbors(node): if neighbor not in visited: visited.add(neighbor) queue.append(neighbor) steps += 1 return -1

#2. Разбор задач

#Задача 1: Binary Tree Level Order Traversal (LeetCode 102) 🟦 Medium

Ссылка: https://leetcode.com/problems/binary-tree-level-order-traversal/

Условие: Дано бинарное дерево. Верните посимвольный обход по уровням (слева направо, уровень за уровнем).

Примеры:

Ввод: root = [3,9,20,null,null,15,7]
Вывод: [[3],[9,20],[15,7]]

Ввод: root = [1]
Вывод: [[1]]

Ввод: root = []
Вывод: []

Ограничения:

  • Количество узлов в дереве в диапазоне [0, 2000]
  • -1000 <= Node.val <= 1000

💡 Подсказка: Используйте очередь. Для обработки каждого уровня фиксируйте размер очереди перед началом итерации: for _ in range(len(queue)).

#Визуализация

Дерево: [3, 9, 20, null, null, 15, 7]

        3              Уровень 0: [3]              queue: [3]
       / \            result: []                   step = 0
      9  20
        / \
       15  7

Шаг 1: Обработка уровня 0
queue: [3] → pop(3) → add(9, 20)
result: [[3]]
queue: [9, 20]

Шаг 2: Обработка уровня 1
queue: [9, 20] → pop(9), pop(20) → add(15, 7)
result: [[3], [9, 20]]
queue: [15, 7]

Шаг 3: Обработка уровня 2
queue: [15, 7] → pop(15), pop(7)
result: [[3], [9, 20], [15, 7]]
queue: [] ← пусто, завершаем

Решение:

from collections import deque def levelOrder(root): if not root: return [] result = [] queue = deque([root]) while queue: level = [] for _ in range(len(queue)): node = queue.popleft() level.append(node.val) if node.left: queue.append(node.left) if node.right: queue.append(node.right) result.append(level) return result

Объяснение:

  • Инициализируем очередь с корневым узлом
  • На каждом уровне обрабатываем все узлы текущего уровня (фиксированный размер очереди)
  • Добавляем детей в очередь для следующего уровня

Сложность:

  • Время: O(n) — посещаем каждый узел
  • Память: O(w) — максимальная ширина дерева в очереди

#Задача 2: Binary Tree Right Side View (LeetCode 199) 🟦 Medium

Ссылка: https://leetcode.com/problems/binary-tree-right-side-view/

Условие: Дано бинарное дерево. Представьте, что вы стоите справа от дерева. Верните значения узлов, видимые справа налево (сверху вниз).

Примеры:

Ввод: root = [1,2,3,null,5,null,4]
Вывод: [1,3,4]

Ввод: root = [1,null,3]
Вывод: [1,3]

Ввод: root = []
Вывод: []

Ограничения:

  • Количество узлов в дереве в диапазоне [0, 100]
  • -100 <= Node.val <= 100

💡 Подсказка: Используйте BFS с обработкой по уровням. Добавляйте в результат последний узел каждого уровня.

Решение:

from collections import deque def rightSideView(root): if not root: return [] result = [] queue = deque([root]) while queue: for i in range(len(queue)): node = queue.popleft() if i == len(queue) - 1: # Последний узел уровня result.append(node.val) if node.left: queue.append(node.left) if node.right: queue.append(node.right) return result

Объяснение:

  • Обрабатываем дерево по уровням
  • После popleft() очередь содержит узлы СЛЕДУЮЩЕГО уровня
  • Поэтому i == len(queue) - 1 проверяет последний узел ТЕКУЩЕГО уровня

Сложность:

  • Время: O(n)
  • Память: O(w)

#Задача 3: Minimum Depth of Binary Tree (LeetCode 111) 🟩 Easy

Ссылка: https://leetcode.com/problems/minimum-depth-of-binary-tree/

Условие: Дано бинарное дерево. Найдите его минимальную глубину.

Минимальная глубина — это количество узлов вдоль кратчайшего пути от корневого узла до ближайшего листового узла.

Примеры:

Ввод: root = [3,9,20,null,null,15,7]
Вывод: 2

Ввод: root = [2,null,3,null,4,null,5,null,6]
Вывод: 5

Ограничения:

  • Количество узлов в дереве в диапазоне [0, 10⁵]
  • -1000 <= Node.val <= 1000

💡 Подсказка: Используйте BFS. Первый найденный лист даёт минимальную глубину.

Решение:

from collections import deque def minDepth(root): if not root: return 0 queue = deque([(root, 1)]) while queue: node, depth = queue.popleft() # Первый найденный лист — минимальная глубина if not node.left and not node.right: return depth if node.left: queue.append((node.left, depth + 1)) if node.right: queue.append((node.right, depth + 1)) return 0

Объяснение:

  • BFS гарантирует, что первый найденный лист — ближайший
  • Важно проверять оба условия: not node.left AND not node.right

Сложность:

  • Время: O(n)
  • Память: O(w)

#3. ⚠️ Common Mistakes

#❌ Ошибка 1: Забыли обрабатывать уровень целиком

Проблема: При подсчёте шагов или обработке уровней важно обрабатывать весь уровень за раз.

# ❌ Неправильно — обрабатываем по одному элементу steps = 0 while queue: node = queue.popleft() if is_target(node): return steps for neighbor in neighbors(node): queue.append(neighbor) steps += 1 # Ошибка: увеличиваем на каждый элемент! # ✅ Правильно — обрабатываем весь уровень steps = 0 while queue: for _ in range(len(queue)): # Фиксируем размер уровня node = queue.popleft() if is_target(node): return steps for neighbor in neighbors(node): if neighbor not in visited: visited.add(neighbor) queue.append(neighbor) steps += 1 # Увеличиваем после обработки всего уровня

Почему это неправильно: steps должен увеличиваться после обработки всех узлов текущего уровня, а не после каждого узла.


#❌ Ошибка 2: Забыли помечать посещённые

Проблема: В графах с циклами BFS зациклится без проверки visited.

# ❌ Неправильно — нет проверки visited queue = deque([start]) while queue: node = queue.popleft() for neighbor in neighbors(node): queue.append(neighbor) # Может зациклиться! # ✅ Правильно — помечаем посещённые queue = deque([start]) visited = {start} while queue: node = queue.popleft() for neighbor in neighbors(node): if neighbor not in visited: visited.add(neighbor) queue.append(neighbor)

Почему это неправильно: В графе с циклами или обратными рёбрами BFS будет бесконечно обходить одни и те же узлы.


#❌ Ошибка 3: Неправильная инициализация visited

Проблема: Начальный узел должен быть помечен как посещённый сразу.

# ❌ Неправильно — start не помечен queue = deque([start]) visited = set() # Пустой! while queue: node = queue.popleft() visited.add(node) # Добавляем при извлечении # start может быть добавлен повторно через соседей! # ✅ Правильно — start помечен сразу queue = deque([start]) visited = {start} # Сразу добавляем start

Почему это неправильно: Начальный узел может быть добавлен повторно через соседей.


#4. Шпаргалка

ЗадачаКлючевая идея
Level Orderfor _ in range(len(queue))
Right Side ViewПоследний узел уровня (i == len(queue) - 1)
Min DepthПервый лист = минимальная глубина

#5. Заключение

BFS: Основы — базовый паттерн для уровневого обхода.

Ключевые приёмы:

  1. for _ in range(len(queue)) — обработка уровня
  2. Помечайте visited сразу при добавлении в очередь
  3. Первый найденный лист в BFS — ближайший (для Min Depth)

Далее: BFS: Деревья