LeetCode || Sort List
阿新 • • 發佈:2019-02-19
Sort List
Sort a linked list in O(n log n) time using constant space complexity.
對一個連結串列進行排序,且時間複雜度要求為 O(n log n) ,空間複雜度為常量。一看到 O(n log n) 的排序,首先應該想到歸併排序和快速排序,但是通常我們使用這兩種排序方法時都是針對陣列的,現在是連結串列了。
歸併排序法:在動手之前一直覺得空間複雜度為常量不太可能,因為原來使用歸併時,都是 O(N)的,需要複製出相等的空間來進行賦值歸併。對於連結串列,實際上是可以實現常數空間佔用的。利用歸併的思想,遞迴地將當前連結串列分為兩段,然後merge,分兩段的方法是使用 fast-slow 法,用兩個指標,一個每次走兩步,一個走一步,知道快的走到了末尾,然後慢的所在位置就是中間位置,這樣就分成了兩段。merge時,把兩段頭部節點值比較,用一個
p 指向較小的,且記錄第一個節點,然後 兩段的頭一步一步向後走,p也一直向後走,總是指向較小節點,直至其中一個頭為NULL,處理剩下的元素。最後返回記錄的頭即可。程式碼如下:
快速排序:使用快排也行,就是每次利用頭節點作為基準,將小於它的交換到連結串列左側,大於它的放在右側,最後把它換到中間某個位置,然後遞迴處理左側和右側。但是相對於歸併來說,它的元素交換次數太多了,可能會超時。
class Solution { public: ListNode *sortList(ListNode *head) { if(!head||!head->next) return head; return mergeSort(head); } ListNode * mergeSort(ListNode *head){ if(!head||!head->next) //just one element return head; ListNode *p=head, *q=head, *pre=NULL; while(q&&q->next!=NULL){ q=q->next->next; pre=p; p=p->next; //divide into two parts } pre->next=NULL; ListNode *lhalf=mergeSort(head); ListNode *rhalf=mergeSort(p); //recursive return merge(lhalf, rhalf); //merge } ListNode * merge(ListNode *lh, ListNode *rh){ ListNode *temp=new ListNode(0); ListNode *p=temp; while(lh&&rh){ if(lh->val<=rh->val){ p->next=lh; lh=lh->next; } else{ p->next=rh; rh=rh->next; } p=p->next; } if(!lh) p->next=rh; else p->next=lh; p=temp->next; temp->next=NULL; delete temp; return p; } };
快速排序:使用快排也行,就是每次利用頭節點作為基準,將小於它的交換到連結串列左側,大於它的放在右側,最後把它換到中間某個位置,然後遞迴處理左側和右側。但是相對於歸併來說,它的元素交換次數太多了,可能會超時。