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,處理剩下的元素。最后返回記錄的頭即可。
主要考察3個知識點,
知識點1:歸並排序的整體思想
知識點2:找到一個鏈表的中間節點的方法
知識點3:合並兩個已排好序的鏈表為一個新的有序鏈表
歸並排序的基本思想是:找到鏈表的middle節點,然后遞歸對前半部分和后半部分分別進行歸並排序,最后對兩個以排好序的鏈表進行Merge。
知識點1:歸並排序的整體思想
知識點2:找到一個鏈表的中間節點的方法
知識點3:合並兩個已排好序的鏈表為一個新的有序鏈表
歸並排序的基本思想是:找到鏈表的middle節點,然后遞歸對前半部分和后半部分分別進行歸並排序,最后對兩個以排好序的鏈表進行Merge。
/** * 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||head->next==NULL) return head; return mergeSort(head); } ListNode* mergeSort(ListNode*head) { if(head->next==NULL) return head; ListNode* pHead,*qHead,*pre; pHead=head; qHead=head; pre=NULL; while(qHead!=NULL&&qHead->next!=NULL) { qHead=qHead->next->next; pre=pHead; pHead=pHead->next; } pre->next=NULL; ListNode *l,*r; l=mergeSort(head); r=mergeSort(pHead); return merge(l,r); } ListNode* merge(ListNode *l,ListNode*r) { ListNode *pRes=new ListNode(0); ListNode *temp=pRes; while(l!=NULL&&r!=NULL) { if(l->val<=r->val) { temp->next=l; temp=temp->next; l=l->next; } else { temp->next=r; temp=temp->next; r=r->next; } } if(l!=NULL) temp->next=l; if(r!=NULL) temp->next=r; temp=pRes->next; delete pRes; return temp; } };