Разбираем задачу flatten linked list — скрытую версию слияния K отсортированных списков. Научитесь видеть паттерн и решать оптимально с кодом на Python.
Представьте: на собеседовании дают связный список с указателями next и bottom, все вертикальные списки уже отсортированы. Половина кандидатов начинает паниковать — а сильные сразу видят flatten linked list как задачу на слияние K отсортированных списков. Давайте научимся видеть этот паттерн.
Дан связный список, где указатель next соединяет разные списки горизонтально, а bottom — узлы по вертикали. Каждый вертикальный список уже отсортирован. Нужно «сплющить» всю структуру в один отсортированный связный список, используя только указатель bottom.
Пример:
5 -> 10 -> 19 -> 28
| | | |
7 20 22 35
| | |
8 50 40
|
30Вывод:
5 -> 7 -> 8 -> 10 -> 19 -> 20 -> 22 -> 28 -> 30 -> 35 -> 40 -> 50Первый интуитивный способ:
Вот реализация на Python:
class Node:
def __init__(self, data):
self.data = data
self.next = None
self.bottom = None
def flatten_brute(root):
values = []
current = root
# Собираем все значения
while current:
temp = current
while temp:
values.append(temp.data)
temp = temp.bottom
current = current.next
# Сортируем
values.sort()
# Перестраиваем список
if not values:
return None
new_root = Node(values[0])
curr = new_root
for val in values[1:]:
curr.bottom = Node(val)
curr = curr.bottom
return new_rootСложность: O(N log N) по времени, O(N) по памяти, где N — общее количество узлов.
Проблема: мы игнорируем тот факт, что каждый вертикальный список уже отсортирован. А это ключевая подсказка.
Если в задаче есть несколько отсортированных списков и их нужно объединить в один — это классический паттерн Merge K Sorted Lists. Для flatten linked list мы применяем рекурсивное слияние справа налево.
root.next = flatten(root.next)return merge(root, root.next)merge используем стандартную логику слияния двух отсортированных списков через указатель bottomРеализация на Python:
class Node:
def __init__(self, data):
self.data = data
self.next = None
self.bottom = None
def merge(a, b):
"""Слияние двух отсортированных списков через bottom"""
dummy = Node(0)
current = dummy
while a and b:
if a.data <= b.data:
current.bottom = a
a = a.bottom
else:
current.bottom = b
b = b.bottom
current = current.bottom
current.next = None # Обнуляем next, чтобы не было циклов
if a:
current.bottom = a
else:
current.bottom = b
return dummy.bottom
def flatten(root):
"""Основная функция flatten linked list"""
if root is None or root.next is None:
return root
# Рекурсивно сплющиваем правую часть
root.next = flatten(root.next)
# Сливаем текущий список с правой частью
return merge(root, root.next)Пусть вход:
5 -> 10 -> 19
| | |
7 20 22
| |
8 50
|
30Шаг 1: Сливаем 10 -> 20 и 19 -> 22 -> 50:
Результат: 10 -> 19 -> 20 -> 22 -> 50
Шаг 2: Сливаем 5 -> 7 -> 8 -> 30 и 10 -> 19 -> 20 -> 22 -> 50:
Результат: 5 -> 7 -> 8 -> 10 -> 19 -> 20 -> 22 -> 30 -> 50
Пусть N — общее количество узлов, K — количество вертикальных списков.
Рекурсия гарантирует, что flatten(root.next) всегда возвращает отсортированный сплющенный список. После этого задача сводится к слиянию двух отсортированных списков — стандартной операции, которую вы уже знаете.
Ключевой инсайт: flatten linked list — это не новая задача, а знакомая Merge K Sorted Lists в disguise.
Когда на собеседовании видите сложную структуру с несколькими отсортированными подсписками — ищите паттерн слияния. Прямо сейчас: откройте LeetCode, найдите задачу «Flatten a Multilevel Doubly Linked List» и решите её этим методом. Затем попробуйте задачу «Merge k Sorted Lists» — вы увидите, что техника та же.
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →