Быстрый и медленный указатели

Начало цикла в связном списке

Найти узел, с которого начинается цикл в связном списке

Средний

Постановка задачи

Описание (LeetCode - 142. Linked List Cycle II)

Дана голова связного списка head. Нужно вернуть узел, с которого начинается цикл. Если цикла нет, нужно вернуть null.

Цикл есть, если какой-то узел в списке ссылается на один из уже пройденных узлов через указатель next.

Исходный связный список нельзя изменять.

Параметр pos обозначает индекс узла, на который ссылается указатель next последнего узла (tail). Индексация начинается с 0. Если цикла нет, pos равен -1. Параметр pos не передается в функцию и используется только в тестах и описании.

Пример 1:

head -> 3 -> 2 -> 0 -> -4
             ^          |
             |          |
             +----------+

head = [3, 2, 0, -4], pos = 1

Результат:

узел со значением 2

Пояснение:

Последний узел указывает на узел с индексом 1, то есть на узел со значением 2.

Пример 2:

head = [1, 2], pos = 0

Результат:

узел со значением 1

Пример 3:

head = [1], pos = -1

Результат:

null

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

  • Количество узлов в списке от 0 до 10⁴
  • -10⁵ <= Node.val <= 10⁵
  • pos не передается в функцию, он используется только для описания цикла

Решение

В задаче Цикл в связном списке мы проверяли только факт наличия цикла. Здесь требуется найти конкретный узел, в котором цикл начинается.

Простое решение - сохранять посещенные узлы в хеш-множество. Первый узел, встреченный повторно, и будет началом цикла. Но такое решение требует O(n) дополнительной памяти.

Алгоритм Флойда (быстрый и медленный указатели) позволяет найти начало цикла за O(1) по памяти.

Перейдите на Premium, чтобы продолжить

Разблокируйте доступ к этой статье и всем остальным материалам с NowInterview Premium

Перейти на Premium