在 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)); }