考点
题解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| class Solution { private: ListNode* MergeList(ListNode* l1, ListNode* l2) { if (l1 == nullptr) return l2; if (l2 == nullptr) return l1; if (l1->val < l2->val) { l1->next = MergeList(l1->next, l2); return l1; } else { l2->next = MergeList(l1, l2->next); return l2; } }
ListNode* MergeSort(ListNode* head) { ListNode *dummyHead = new ListNode(-1, head), *cur = dummyHead; int len = 0; while (cur->next != nullptr) { cur = cur->next; len++; }
for (int subLen = 1; subLen < len; subLen *= 2) { ListNode *curNew = dummyHead, *cur = dummyHead->next; while (cur != nullptr) { ListNode *leftHead = cur; for (int i = 1; i < subLen && cur->next != nullptr; cur = cur->next, i++); ListNode *rightHead = cur->next; cur->next = nullptr; cur = rightHead; for (int i = 1; i < subLen && cur != nullptr && cur->next != nullptr; cur = cur->next, i++); if (cur != nullptr) { ListNode *nextLeftHead = cur->next; cur->next = nullptr; cur = nextLeftHead; } curNew->next = MergeList(leftHead, rightHead); while (curNew->next != nullptr) curNew = curNew->next; } } return dummyHead->next; }
public: ListNode* sortList(ListNode* head) { return MergeSort(head); } };
|
思路
题目要求在O(nlogn)
时间复杂度和常数级空间复杂度下对链表进行排序
考虑时间复杂度,满足要求的有归并排序、堆排序与快速排序;后两者在链表实现上较难,所以选择归并排序
首先写出递归版本的归并排序,思路很简单
- 在递归的去方向中:每次找到链表的中点,并利用递归分割成左子链表和右子链表
- 在递归的回方向中:合并左右子链表;因为子链表均有序,可以参考
21. 合并两个有序链表
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class Solution { private: ListNode* MergeList(ListNode* l1, ListNode* l2) { if (l1 == nullptr) return l2; if (l2 == nullptr) return l1; if (l1->val < l2->val) { l1->next = MergeList(l1->next, l2); return l1; } else { l2->next = MergeList(l1, l2->next); return l2; } }
ListNode* MergeSort(ListNode* head) { if (head == nullptr || head->next == nullptr) return head; ListNode *slow = head, *fast = slow; while (fast->next != nullptr && fast->next->next != nullptr) { slow = slow->next; fast = fast->next->next; } ListNode *newHead = slow->next; slow->next = nullptr; return MergeList(MergeSort(head), MergeSort(newHead)); }
public: ListNode* sortList(ListNode* head) { return MergeSort(head); } };
|
但递归是自顶向下的写法,显然空间复杂度是O(logn)
并不满足题目需求;所以需要使用自底向上的写法
递归的去方向不断地拆分链表,故而消耗了额外的栈空间;若用迭代来替代递归的拆分
动作,就不会有额外的空间损耗
自底向上的迭代思路如图所示,其中有序子链表合并
操作的代码直接参考21. 合并两个有序链表
即可
编程如下,为了可读性部分逻辑有重复,简化后就是题解代码的模样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| class Solution { private: ListNode* MergeList(ListNode* l1, ListNode* l2) { if (l1 == nullptr) return l2; if (l2 == nullptr) return l1; if (l1->val < l2->val) { l1->next = MergeList(l1->next, l2); return l1; } else { l2->next = MergeList(l1, l2->next); return l2; } }
ListNode* MergeSort(ListNode* head) { ListNode *dummyHead = new ListNode(-1, head), *cur = dummyHead; int len = 0; while (cur->next != nullptr) { cur = cur->next; len++; }
for (int subLen = 1; subLen < len; subLen *= 2) { ListNode *curNew = dummyHead, *cur = dummyHead->next; while (cur != nullptr) { ListNode *leftHead = cur; for (int i = 1; i < subLen && cur->next != nullptr; cur = cur->next, i++); if (cur->next == nullptr) { curNew->next = leftHead; cur = nullptr; } else { ListNode *rightHead = cur->next; cur->next = nullptr; cur = rightHead; for (int i = 1; i < subLen && cur->next != nullptr; cur = cur->next, i++); ListNode *nextLeftHead = cur->next; cur->next = nullptr; cur = nextLeftHead; curNew->next = MergeList(leftHead, rightHead); while (curNew->next != nullptr) curNew = curNew->next; } } } return dummyHead->next; }
public: ListNode* sortList(ListNode* head) { return MergeSort(head); } };
|