2095. Delete the Middle Node of a Linked List
Содержание
Задача
Дан связный список (linked list). Задача — удалить средний узел из этого списка и вернуть начало(head) измененного списка.
Подсказки
Мы можем использовать метод двух указателей для того, чтобы найти средний узел в одном проходе по списку, где второй указатель проходит весь список в два раза быстрее первого указателя.
Подход
- Используем два указателя для прохода по списку: один медленный и один быстрый. Оба начинают с головного узла списка.
- Быстрый указатель будет двигаться в два раза быстрее медленного. Каждый шаг он перескакивает через два узла, в то время как медленный только на один. Таким образом, когда быстрый указатель достигнет конца список, первый указатель будет на середине.
- По мере продвижения указателей сохраняем узел, предшествующий медленному поинтеру (
prev
), так как именно егоnext
нам нужно будет изменить. - Когда быстрый указатель достигнет конца списка или окажется на последнем узле, медленный указатель будет указывать на средний узел.
- Удаляем средний узел.
Алгоритм
- Инициализируем два указателя: один медленный (
p1
), другой быстрый (p2
), и третий указательprev
. - Обновляем указатели до момента достижения быстрым конца списка:
- Быстрый указатель на каждом шаге перепрыгивает через
next
. - Временный (
prev
) указатель сохраняет ссылку на медленный указатель до его изменения - Медленный указатель на каждом шаге обновляется до
next
.
- Быстрый указатель на каждом шаге перепрыгивает через
- Удаляем средний элемент путем обновления ссылки в указателе
prev.next
наp1.next
Решение
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def deleteMiddleNode(head: ListNode) -> ListNode:
if not head.next:
return None
p1 = head # быстрый
p2 = head # медленный
prev = None # предыдущий. Будет в середине
while p2 and p2.next:
prev = p1
p1 = p1.next
p2 = p2.next.next
prev.next = p1.next
return head