Sort a linked list in O(n log n) time using constant space complexity.
分析:
题目要求对链表进行排序,如果采用插入、冒泡等排序方式,则时间复杂度将是O(n*n),达不到题目要求的O(n log n)的要求。O(n log n)复杂度的有快排和归并排序,对于链表来说,归并排序更适合一点。这样题目转换为将一个链表拆分成两个有序的链表,然后再进行归并排序。关键就在于链表中点的获取。对于链表中点获取可以采取快慢指针法,快指针每次进2步,慢指针每次一步,这样快指针到达终点时,慢指针将处于链表中点处。
代码如下,执行时间约 68ms:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) {
ListNode* head =NULL, *tmp;
while (l1 && l2)
{
if (l1->val <= l2->val)
{
if (!head)
{
head = l1;
tmp = head;
}else{
tmp ->next= l1;
tmp = tmp->next;
}
l1 = l1->next;
}else{
if (!head)
{
head = l2;
tmp = head;
}
else
{
tmp ->next = l2;
tmp = tmp->next;
}
l2 = l2->next;
}
}
if (l1)
{
tmp->next = l1;
}
if (l2)
{
tmp->next = l2;
}
return head;
}
ListNode *sortList(ListNode *head) {
ListNode tmpNode = ListNode(INT_MIN);
if (head==NULL || head->next==NULL)
{
return head;
}
ListNode *p1=head, *p2=head->next;
while (p2 && p2->next)
{
p1 = p1->next;
p2 =p2->next->next;
}
p2 = p1->next;
p1->next= NULL;
return mergeTwoLists(sortList(head), sortList(p2));
}
};
2018-11-12:补充
上述方法虽满足了O(nlogn)的时间和O(1)的空间复杂度,但通过快慢指针方法找链表中点,需要首先遍历链表,浪费了很多操作。下面这种方法也是归并排序,但不需要扫描链表获得链表中点、也不递归。在实现上比之前的快很多。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
static struct ListNode *merge(struct ListNode*a, struct ListNode*b) {
struct ListNode head, *tail;
tail = &head;
while (a && b) {
if ((a->val <= b->val) ) {
tail->next = a;
a = a->next;
} else {
tail->next = b;
b = b->next;
}
tail = tail->next;
}
tail->next = a ? : b;
return head.next;
}
#define MAX_LIST_LENGTH_BITS 31
struct ListNode* sortList(struct ListNode* head) {
struct ListNode *part[MAX_LIST_LENGTH_BITS + 1];
int lev;
int max_lev = 0;
struct ListNode *bnode;
if (head == NULL || head->next==NULL)
return head;
memset(part, 0, sizeof(part));
bnode = head;
while (bnode) {
struct ListNode *cur = bnode;
bnode = bnode->next;
cur->next = NULL;
for (lev = 0; part[lev]; lev++) {
cur = merge(part[lev], cur);
part[lev] = NULL;
}
if (lev > max_lev) {
if ((lev >= MAX_LIST_LENGTH_BITS)) {
lev--;
}
max_lev = lev;
}
part[lev] = cur;
}
for (lev = 0; lev < max_lev; lev++)
if (part[lev])
bnode = merge(part[lev], bnode);
bnode = merge(part[max_lev], bnode);
return bnode;
}
与之类似的还有
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* sortList(struct ListNode* head) {
struct ListNode *p, *q, *e, **tail;
int k, psize, qsize;
if (!head)
return 0;
int count = 0;
struct ListNode *pHead = head;
p = pHead;
while (p) {
count++;
p = p->next;
}
for (k = 1; k < count; k *= 2) {
tail = &pHead;
for (p = q = pHead; p; p = q) {
/* step 'k' places from p; */
for (psize = 0; q && psize < k; psize++)
q = q->next;
qsize = k;
/* two lists, merge them. */
while (psize || (qsize && q)) {
/* merge the next element */
if (psize == 0 || ((qsize && q) && ((p->val - q->val) >= 0))) {
/* p is empty, or p > q, so q next */
e = q;
q = q->next;
qsize--;
} else {
e = p;
p = p->next;
psize--;
}
e->next = NULL; /* break accidental loops. */
*tail = e;
tail = &e->next;
}
}
}
return pHead;
}