Признак в условии
- узлы { value, next }, произвольного доступа по индексу нет
- «развернуть», «найти середину», «есть ли цикл», «n-й с конца»
- требуется O(1) дополнительной памяти
Приёмы
Три указателя для разворота: сохранить next → переписать ссылку → сдвинуть оба. Быстрый и медленный: fast делает два шага, slow один - середина и поиск цикла. Фиктивная голова: избавляет от особого случая «меняем первый элемент».
Шаблон
let prev = null, cur = head;
while (cur) {
const next = cur.next; // сохранить ДО перезаписи
cur.next = prev;
prev = cur;
cur = next;
}
return prev; // возвращаем prev, а не cur
const dummy = { next: head }; // фиктивная голова
let slow = dummy, fast = dummy;
Сложность
Время O(n), память O(1).
Частые ошибки
cur.nextпереписан до сохранения next - хвост потерян- возвращают cur (он уже null) вместо prev
- удаление головы не обработано - лечится фиктивным узлом
- в цикле поиска середины проверяют только fast, забывая fast.next
Мнемоника
«Сохрани, переверни, сдвинь»
Не путать с
- Два указателя - быстрый и медленный - это два указателя; отличие в том, что длину заранее не знаешь и назад не ходишь
- Стек - если нужно пройти список задом наперёд, а память не жалко, проще сложить в стек, чем разворачивать
Задачи на этот паттерн
- разворот связного списка
- середина списка
- слияние отсортированных списков
- удалить n-й с конца
- цикл в списке
- список-палиндром
- сложение чисел списками
- перестановка по чётности позиций