归并和快排的方法都要掌握
题目要求时间空间复杂度分别为O(nlogn)和O(1)
时间复杂度是 O(nlogn) 的排序算法包括归并排序、堆排序和快速排序(快速排序的最差时间复杂度是 O(n^2),其中最适合链表的排序算法是归并排序。
归并排序基于分治算法。最容易想到的实现方式是自顶向下的递归实现,考虑到递归调用的栈空间,自顶向下归并排序的空间复杂度是O(logn)。如果要达到 O(1)的空间复杂度,则需要使用自底向上的实现方式。
解答一:归并排序(递归法,空间复杂度是O(logn))
/** * 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) {
//1、递归结束条件
if(head == nullptr || head->next == nullptr) return head;
//2、找到链表中间节点并且断开链表 & 递归下探
ListNode* midnode = middlenode(head);
ListNode* rightnode = midnode->next;
midnode->next = nullptr;
ListNode* left = sortList(head);
ListNode* right = sortList(rightnode);
//合并有序的链表
return mergeTwoLists(left,right);
}
//找到链表中间节点(876、链表的中间节点)
ListNode* middlenode(ListNode* head){
if(head == nullptr || head->next == nullptr) return head;
ListNode* slow = head;
ListNode* fast = head;
while(fast!=nullptr && fast->next != nullptr){
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
//合并两个有序链表(21、合并两个有序链表)
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode* dummy = new ListNode(-1);
ListNode * pre = dummy;
while(list1 != nullptr && list2 != nullptr){
if(list1->val > list2->val){
pre->next = list2;
list2 = list2->next;
pre = pre->next;
}else{
pre->next = list1;
list1 = list1->next;
pre = pre->next;
}
}
pre->next = list1 !=nullptr ? list1:list2;
return dummy->next;
}
};
解答二:归并排序(从底至顶直接合并)
思路:
current = dummy.next;
tail = dummy;
for (step = 1; step < length; step *= 2) {
while (current) {
// left->@->@->@->@->@->@->null
left = current;
// left->@->@->null right->@->@->@->@->null
right = cut(current, step); // 将 current 切掉前 step 个头切下来。
// left->@->@->null right->@->@->null current->@->@->null
current = cut(right, step); // 将 right 切掉前 step 个头切下来。
// dummy.next -> @->@->@->@->null,最后一个节点是 tail,始终记录
// ^
// tail
tail.next = merge(left, right);
while (tail->next) tail = tail->next; // 保持 tail 为尾部
}
}
作者:ivan_allen
链接:https://leetcode-cn.com/problems/sort-list/solution/148-pai-xu-lian-biao-bottom-to-up-o1-kong-jian-by-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
代码
class Solution {
public:
ListNode* sortList(ListNode* head) {
ListNode dummyHead(0);
dummyHead.next = head;
auto p = head;
int length = 0;
while (p) {
++length;
p = p->next;
}
for (int size = 1; size < length; size <<= 1) {
auto cur = dummyHead.next;
auto tail = &dummyHead;
while (cur) {
auto left = cur;
auto right = cut(left, size); // left->@->@ right->@->@->@...
cur = cut(right, size); // left->@->@ right->@->@ cur->@->...
tail->next = merge(left, right);
while (tail->next) {
tail = tail->next;
}
}
}
return dummyHead.next;
}
ListNode* cut(ListNode* head, int n) {
auto p = head;
while (--n && p) {
p = p->next;
}
if (!p) return nullptr;
auto next = p->next;
p->next = nullptr;
return next;
}
ListNode* merge(ListNode* l1, ListNode* l2) {
ListNode dummyHead(0);
auto p = &dummyHead;
while (l1 && l2) {
if (l1->val < l2->val) {
p->next = l1;
p = l1;
l1 = l1->next;
} else {
p->next = l2;
p = l2;
l2 = l2->next;
}
}
p->next = l1 ? l1 : l2;
return dummyHead.next;
}
};
作者:ivan_allen
链接:https://leetcode-cn.com/problems/sort-list/solution/148-pai-xu-lian-biao-bottom-to-up-o1-kong-jian-by-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
文章评论