在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:
输入: 4->2->1->3 输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0 输出: -1->0->3->4->5
这道题要求对链表排序且对时间和空间复杂度有要求,主要用归并排序的思想。每次把链表一分为二(快慢指针法),然后对两个分链表进行合并,这里在discuss部分看到一个很精简也很容易理解的代码,用了双重递归,具体分析过程不做解释,对递归的调用再强调一遍要注意边界条件和细节处理。由快慢指针分割后,原链表根据长度不同会出现以下情况:
原链表:
1:nullptr或者长度为1,直接return
2:长度为2:
3:长度为3:
当长度为3时,又被分为长度为1和长度为2的子情况,所以只有情况1和情况2。
为什么要讨论边界情况,因为merge函数对传入的两个链表进行合并,就需要知道在分割的最底层情况两个子链表l1和l2会出现什么情况,我们在merge函数的合并函数以及开始的非空判断返回时才能考虑周全,不会遗漏情况。
下面是c++代码(时间复杂度O(nlogn),空间复杂度O(n)由于归并排序必须要辅助空间为n的数组):
ListNode* merge(ListNode* l1, ListNode* l2) {
if (!l1 && l2) {
return l2;
}
if (l1 && !l2) {
return l1;
}
if (l1 == l2) {
return l1;
}
if (l1->val < l2->val) {
l1->next = merge(l1->next,l2);
return l1;
}
else {
l2->next = merge(l1, l2->next);
return l2;
}
}
ListNode* sortList(ListNode* head) {
if (!head || !head->next) {
return head;
}
ListNode* slow = head;
ListNode* fast = head;
ListNode* pre = head;
while (fast && fast->next) {
pre = slow;
slow = slow->next;
fast = fast->next->next;
}
pre->next = nullptr;
return merge(sortList(head), sortList(slow));
}