Sort a linked list in O(n log n) time using constant space complexity.
题目很简单,就是对一个单链表进行排序,但是要求时间复杂度为O(nlogn)空间复杂度在常数范围内。
分析:
1)提到排序:按照算法导论上描述:
插入排序,平均时间复杂度O(n2),原地排序
归并排序(O(nlogn)),非原地排序(额外申请空间)
堆排序(O(nlogn)),原地排序
快排(期望:O(nlogn),最坏O(n2)),原地排序
2)由此定位在归并排序和堆排序上,我最初的想法是堆排序,但这里给的是链表,而算法导论中给出的是以数组的形式,行不通了;
3)在Discuss上看了别人的方法(自己没想到),原来就是归并排序,只需改变链表指向就可以了,无需申请额外空间,代码如下:
// Definition for singly-linked list.
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode *sortList(ListNode *head) {
if (head==NULL)
{
return NULL;
}
//计算List长度
int listLen=0;
ListNode *p=head;
while (p!=NULL)
{
listLen++;
p=p->next;
}
head=MergeSort(head,listLen);
return head;
}
ListNode* merge(ListNode *p1,ListNode *p2)
{
ListNode *phead;
ListNode *head;
if (p1->val>=p2->val)
{
phead=p2;
p2=p2->next;
}
else
{
phead=p1;
p1=p1->next;
}
head=phead;
phead->next=NULL;
while (p1!=NULL&&p2!=NULL)
{
if (p1->val>=p2->val)
{
phead->next=p2;
p2=p2->next;
}
else
{
phead->next=p1;
p1=p1->next;
}
phead=phead->next;
phead->next=NULL;
}
if (p1==NULL)
{
phead->next=p2;
}
else
{
phead->next=p1;
}
return head;
}
ListNode* MergeSort(ListNode *head,int listLen)
{
if (listLen==1||listLen==0)
{
return head;
}
int mid=listLen/2;
ListNode *p1;
ListNode *p2;
p2=p1=head;
//分段,查找第二段的起点并设置第一段的终点
int i=1;
while (i<mid)
{
i++;
if (p2!=NULL)
{
p2=p2->next;
}
else
{
break;
}
}
if (p2!=NULL)
{
ListNode *p1buttom=p2;
p2=p2->next;
p1buttom->next=NULL;
}
p1=MergeSort(p1,mid);
p2=MergeSort(p2,listLen-mid);
head=merge(p1,p2);
return head;
}
};