328. Odd Even Linked List
Содержание
Задача
Дан односвязный список и задача переставить его узлы таким образом, чтобы все узлы с нечетными индексами шли перед всеми узлами с четными индексами.
Вариант решения 1
Рассмотрим вариант решения более простой для понимания и реализации.
Подсказки
Использовать два связных списка.
Подход
Во время прохода по связному списку указатель для чётных узлов добавлять связанный список с четными, то же самое делать с нечетными.
В конце прохода список с четными узлами добавить в конец списка с нечетными узлами.
Алгоритм
- Объявляем 2 пустых связных списка (
even_head
,odd_head
) - Объявляем два указателя на каждый список (
even
,`odd). Данные указатели будут перемещаться по своим спискам. - Проходим по списку
head
:- если текущий указатель - четный, добавляем его в
even_head
(обновляем значение указателя списка). - Переставляем указатель на следующий.
even = even.next
- Шаги 1-2 для нечетного указателя соответсвенно.
- если текущий указатель - четный, добавляем его в
- Переходим к следующему указателю в
head
. - Соединяем два списка. Список с четные указателями становится следующим после списка с нечетными указателями.
- Так как четные указатели должны стоять в самом конце нового списка, то обновляем
even.next = None
, потому что после него ничего не должно идти. - Добавляем
even_head
к спискуodd_head
в конец.
- Так как четные указатели должны стоять в самом конце нового списка, то обновляем
- Возвращаем
odd_head
Решение
class Solution:
def oddEvenList(self, head: Optional[ListNode]) -> Optional[ListNode]:
odd_head = ListNode(0)
even_head = ListNode(0)
odd = odd_head
even = even_head
is_odd = True
while head:
if is_odd:
odd.next = head
odd = odd.next
else:
even.next = head
even = even.next
head = head.next
is_odd = not is_odd
even.next = None # самый последний узел
odd.next = even_head.next # head в конец списка
return odd_head.next
Вариант решения 2
Подсказки
Использовать указатели. Четный указатель будет головным для четных, нечетный для нечетных. Четный и нечетный по мере прохождения можно менять местами.
Подход
Абстрактная идея:
- превратить список
head
в список из нечетных по счету узлов. - превратить список
even_head
из спискаhead
с содержанием только четных узлов
- Инициализация указателей: Инициализируем указатели для нечетных и четных узлов, а также сохраняем начальный четный узел, который будет использован после того, как пройдем весь список.
- Перестановка узлов: Проходим по списку, меняя местами нечетные и четные узлы.
- Обновляем
next
для нечетного путем взятияnext
у четного:odd.next = even.next
- Перемещаем указатель для нечетного вперед:
odd = odd.next
- 1 и 2 шаги проделываем для четного указателя. 💡 четный указатель обновляет ссылки с обновленного четного указателя.
- Обновляем
- Соединение списков: После того как все узлы переставлены, последний нечетный узел должен указывать на первый четный узел.
Пример для 1,2,3,4,5
:
- Инициализация указателей:
- Указатель
odd
указывает на узел с значением 1. состояние списка:1-2-3-4-5
- Указатель
even
указывает на узел с значением 2. состояние списка:2-3-4-5
- Указатель
even_head
указывает на узел с значением 2. состояние списка:2-3-4-5
- Первый проход:
odd.next
будет указывать на узел, следующий заeven
: 1-2 => 1-3,odd.next = 3
.- Обновляем
odd
наodd.next
.odd = 3
,odd.next = 4
. even.next
будет указывать на узел, следующий за новымodd
: 2-3 => 2->4,even.next = 4
.- Перемещаем
even
наeven.next
- Текущее состояние списков
head
:1-3-4-5
,even_head
:2-4-5
- Второй проход:
odd.next
будет указывать на узел, следующий заeven
(узел с значением 6)- Обновляем
odd
наodd.next
. с значением 6 even.next
будет указывать на узел, следующий за новымodd
(узел с значением 5)- Перемещаем
even
на узел с значением 5 - Текущее состояние списка:
1-3-5
.2-4
- Объединение четных и нечетных:
После окончания всех проходов, установить odd.next
на узел, на который указывает even_head
.
Алгоритм
- Инициализируем указатели
odd
иeven
на начальные нечетные и четные узлы. - Сохраняем начальный четный узел в переменной
even_head
. - Пока четные и нечетные узлы не
None
, продолжаем перестановку. - В конце соединяем последний нечетный узел с
even_head
.
Решение
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def oddEvenList(head: ListNode) -> ListNode:
if not head:
return head
odd = head
even = head.next
even_head = even
while even and even.next:
odd.next = even.next
odd = odd.next
even.next = odd.next
even = even.next
# Соединяем последний нечетный узел с первым четным
odd.next = even_head
return head