题目
描述
给定一个节点数为 n 的无序单链表,对其按升序排序。
数据范围:0<n≤100000
要求:空间复杂度 O(n),时间复杂度 O(nlogn)
示例 1
输入:
[1,3,2,4,5]
返回值:
{1,2,3,4,5}
复制代码
示例 2
输入:
[-1,0,-2]
返回值:
{-2,-1,0}
复制代码
分析
思路一
实际上刨除链表的形式,我们知道,这就是一个排序问题,首先我们能想到的比较简单的就是插入排序方式。
将链表分为已排序的部分(开始时只有一个元素)和后面未排序的部分,遍历未排序的部分元素;
在已排序的部分中从前往后遍历查找合适的位置(元素大小大于当前待排序的元素,或走到了已排序部分的末尾);
将当前待排序元素插入到找出的合适位置,遍历直到末尾,整个链表已排序完毕。
上述方案中需要增加一个表头元素,空间复杂度为 O(1),最差情况下时间复杂度为 O(n^2)。
思路二
对于排序问题,归并排序的时间复杂度可以达到 O(nlogn),我们就来看看如何将链表排序的问题分解成子问题。
首先我们要将链表分为前后两个部分,这里我们可以用到快慢指针,快指针每次走两步,慢指针走一步,这样可以找到链表的中点;然后对这两个部分分别做排序处理,最后将得到的结果使用两个有序链表排序的算法连接成一条链表。
特别地,子问题中,如果头指针为空或头指针的 next 为空,视为已排序,立即返回。
步骤如下:
step 1:首先判断链表为空或者只有一个元素,直接就是有序的。
step 2:准备三个指针,快指针 right 每次走两步,慢指针 mid 每次走一步,前序指针 left 每次跟在 mid 前一个位置。三个指针遍历链表,当快指针到达链表尾部的时候,慢指针 mid 刚好走了链表的一半,正好是中间位置。
step 3:从 left 位置将链表断开,刚好分成两个子问题开始递归。
step 4:将子问题得到的链表合并。
代码示例
版本一
使用插入排序,使用一个额外的空间 O(1),时间复杂度 O(n^2)
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类 the head node
* @return ListNode类
*/
ListNode* sortInList(ListNode* head) {
// write code here
if (nullptr == head || nullptr == head->next) {
return head;
}
ListNode* pReturn = new ListNode(-1);
pReturn->next = head;
// split the link list
ListNode* pCur = head->next;
head->next = nullptr;
ListNode* pNext = nullptr;
while (nullptr != pCur) {
// find the location
ListNode* pPreSearch = pReturn;
ListNode* pSearch = pReturn->next;
while (nullptr != pSearch) {
if (pSearch->val > pCur->val) {
break;
}
pPreSearch = pSearch;
pSearch = pSearch->next;
}
// link the node
pNext = pCur->next;
pCur->next = pPreSearch->next;
pPreSearch->next = pCur;
pCur = pNext;
}
return pReturn->next;
}
};
复制代码
版本二
使用归并排序的方式,时间复杂度 O(nlogn),空间复杂度 O(n)
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类 the head node
* @return ListNode类
*/
ListNode* sortInList(ListNode* head) {
// write code here
return MergeSort(head);
}
ListNode* MergeSort(ListNode* head){
if (nullptr == head || nullptr == head->next) {
return head;
}
ListNode *pQuick = head;
ListNode *pSlow = head;
ListNode *pPre = nullptr;
while(pQuick && pQuick->next){
pQuick = pQuick->next->next;
pPre = pSlow;
pSlow = pSlow->next;
}
pPre->next = nullptr;
ListNode* pLeft = MergeSort(head);
ListNode* pRight = MergeSort(pSlow);
return Merge2List(pLeft, pRight);
}
ListNode* Merge2List(ListNode *head1,ListNode* head2){
if(nullptr == head1){
return head2;
}
if(nullptr == head2){
return head1;
}
ListNode *pReturn = new ListNode(-1);
ListNode *pCur = pReturn;
while(nullptr != head1 && nullptr != head2){
if(head1->val < head2->val){
pCur->next = head1;
head1 = head1->next;
}else{
pCur->next = head2;
head2 = head2->next;
}
pCur = pCur->next;
}
pCur->next = nullptr == head1 ? head2 : head1;
return pReturn->next;
}
};
复制代码
评论