题目
给定一个链表,请将升序排序后返回。
输入:head = [4,2,1,3]
输出:[1,2,3,4]
要求时间复杂度O(nlogn)、空间复杂度 O(1)
原题链接:https://leetcode.cn/problems/sort-list/
思路
排序中,O(nlogn) 的方法有 快排、堆排、归并等。
最适合链表的排序方式是归并排序。
思路1
自顶向下归并。
先找到中间节点,将链表分成两段。将两段分别进行递归排序后再合并。合并的方式就按《合并两个有序链表》的方式进行即可。
对于最小单位的链表,需要对链表进行割尾。以便把两个独立的链表进行合并。
找中间节点,可通过快慢指针来找。
- 复杂度分析
- 时间复杂度 O(nlogn)。找中间节点为 O(nlogn),归并也是 O(nlogn),所以整体还是 O(nlogn)
- 空间复杂度 O(logn)。这种方式需要递归,层数为 logn。
思路2
自底向上归并。
如果想要做到空间复杂度 O(1),则不能使用递归,采用自底向上的归并。
先将长度为1的子链表两两合并,再将长度为2、4、8… 的子链表两两合并。
注意边界情况的处理。
并用一个 pre 指针来串联子结果。
- 复杂度分析
- 时间复杂度 O(nlogn)。
- 空间复杂度 O(1)
代码
代码1
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
return mergeSort(head, NULL);
}
ListNode* mergeSort(ListNode* head, ListNode* tail) {
if (head == NULL) {
return head;
}
// 对最小单位的链表节点进行分割
if (head->next == tail) {
head->next = NULL;
return head;
}
ListNode* fast = head;
ListNode* slow = head;
while (fast != tail && fast->next != tail) {
fast = fast->next->next;
slow = slow->next;
}
ListNode* head1 = mergeSort(head, slow);
ListNode* head2 = mergeSort(slow, tail);
ListNode* new_head = mergeList(head1, head2);
return new_head;
}
ListNode* mergeList(ListNode* head1, ListNode* head2) {
ListNode* head = new ListNode();
ListNode* cur = head;
while (head1 && head2) {
if (head1->val < head2->val) {
cur->next = head1;
head1 = head1->next;
}
else {
cur->next = head2;
head2 = head2->next;
}
cur = cur->next;
}
if (head1) {
cur->next = head1;
}
if (head2) {
cur->next = head2;
}
return head->next;
}
};
代码2
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
if (head == NULL || head->next == NULL) {
return head;
}
int length = 0;
ListNode* cur = head;
while (cur) {
length++;
cur = cur->next;
}
ListNode* dummyHead = new ListNode(0, head);
for (int sub_length = 1; sub_length < length; sub_length *= 2) {
ListNode* pre = dummyHead;
ListNode* cur = pre->next;
while (cur) {
ListNode* head1 = cur;
for (int i = 0; i < sub_length - 1 && cur; i++) {
cur = cur->next;
}
ListNode* head2 = NULL;
// 第一个链表需要cut;如果cur已经是最后一个节点,则不需要cut,head2直接为NULL
if (cur) {
head2 = cur->next;
cur->next = NULL;
}
cur = head2;
for (int i = 0; i < sub_length - 1 && cur; i++) {
cur = cur->next;
}
// 同样的,如果cur还不是最后一个节点,第二个链表也需要cut
if (cur) {
ListNode* temp = cur->next;
cur->next = NULL;
cur = temp;
}
ListNode* new_head = mergeList(head1, head2);
// 用 pre 来串联子结果
pre->next = new_head;
while(pre->next) {
pre = pre->next;
}
}
}
return dummyHead->next;
}
ListNode* mergeList(ListNode* head1, ListNode* head2) {
ListNode* head = new ListNode();
ListNode* cur = head;
while (head1 && head2) {
if (head1->val < head2->val) {
cur->next = head1;
head1 = head1->next;
}
else {
cur->next = head2;
head2 = head2->next;
}
cur = cur->next;
}
if (head1) {
cur->next = head1;
}
if (head2) {
cur->next = head2;
}
return head->next;
}
};