Сложность: medium
Дан указатель на начало связанного списка. Верните список после его сортировки в порядке возрастания.
Пример:
Input: head = [4,2,1,3]
Output: [1,2,3,4]
👨💻 Алгоритм:
1️⃣Разделение списка (Фаза разделения):
Рекурсивно разделяйте исходный список на две половины. Процесс разделения продолжается до тех пор, пока в связанном списке не останется только один узел. Для разделения списка на две части используется подход с быстрым и медленным указателями, как упоминается в методе поиска середины связанного списка.
2️⃣Сортировка подсписков и их объединение (Фаза слияния):
Рекурсивно сортируйте каждый подсписок и объединяйте их в один отсортированный список. Это аналогично задаче слияния двух отсортированных связанных списков.
3️⃣Иллюстрация процесса сортировки:
Процесс продолжается до тех пор, пока не будет получен исходный список в отсортированном порядке. Например, для связанного списка [10,1,60,30,5] описан процесс сортировки слиянием с использованием подхода сверху вниз. Если у нас есть отсортированные списки list1 = [1,10] и list2 = [5,30,60], следующая анимация иллюстрирует процесс слияния обоих списков в один отсортированный список.
😎 Решение:
var sortList = function (head) {
if (!head || !head.next) return head;
let mid = getMid(head);
let left = sortList(head);
let right = sortList(mid);
return merge(left, right);
function merge(list1, list2) {
let dummyHead = new ListNode();
let tail = dummyHead;
while (list1 && list2) {
if (list1.val < list2.val) {
tail.next = list1;
list1 = list1.next;
} else {
tail.next = list2;
list2 = list2.next;
}
tail = tail.next;
}
tail.next = list1 ? list1 : list2;
return dummyHead.next;
}
function getMid(head) {
let midPrev = null;
while (head && head.next) {
midPrev = midPrev === null ? head : midPrev.next;
head = head.next.next;
}
let mid = midPrev.next;
midPrev.next = null;
return mid;
}
};Ставь 👍 и забирай 📚 Базу знаний
