[C++]LeetCode: 125 Sort List (歸併排序連結串列)
阿新 • • 發佈:2019-02-01
題目:Sort a linked list in O(n log n) time using constant space complexity.
思路:題目要求我們使用常數空間複雜度,時間複雜度為O(nlog(n)). 滿足這個時間複雜度的有快速排序,歸併排序,堆排序。插入排序時間複雜度為O(n^2). 雙向連結串列用快排比較合適,堆排序也可用於連結串列,單項鍊表適合於歸併排序。我們就用歸併排序的思想來完成連結串列的排序。
首先是用快慢雙指標找到連結串列中間的位置,然後分成前後端分別遞迴的歸併排序,最後合併。
Attention:
1. 快慢指標找中間節點的方法,是常用方法,要熟練使用。
//將連結串列分成前後兩部分 雙指標找到中間節點
ListNode* fast = head;
ListNode* slow = head;
while(fast->next != NULL && fast->next->next != NULL)
{
slow = slow->next;
fast = fast->next->next;
}
2. 連結串列的資料結構是如何實現歸併的方法的。定義一個合併後的連結串列,然後把合適的節點放進去。思想和陣列是一樣的,只是連結串列操作不一樣。複雜度:如果這裡我們考慮遞迴的棧空間的話,空間複雜度是O(lg(n))
AC Code:
/** * 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; //將連結串列分成前後兩部分 雙指標找到中間節點 ListNode* fast = head; ListNode* slow = head; while(fast->next != NULL && fast->next->next != NULL) { slow = slow->next; fast = fast->next->next; } ListNode* head2 = slow->next; slow->next = NULL; ListNode* head1 = head; head1 = sortList(head1); //前半段歸併排序 head2 = sortList(head2); //後半段歸併排序 return merge(head1, head2); } private: ListNode* merge(ListNode* h1, ListNode* h2) { ListNode* dummyhead = new ListNode(0); ListNode* mlist = dummyhead; while(h1 != NULL && h2 != NULL) { if(h1->val <= h2->val) { mlist->next = h1; h1 = h1->next; } else { mlist->next = h2; h2 = h2->next; } mlist = mlist->next; } if(h1 != NULL) { mlist->next = h1; } if(h2 != NULL) { mlist->next = h2; } return dummyhead->next; } };
我們也可以不使用遞迴的方法,自底向上的非遞迴版本的歸併排序,空間複雜度就是常數了。可以看下這篇博文:sort list.
排序是面試中很常見和基礎的一個主題,我們需要對各種常見的排序演算法要熟悉。尤其是演算法的原理,很多題目雖然沒有直接考察排序的實現,但是會用到其中的思想,比如經典的topK問題,用到了快排的原理。這篇文章中有提到,可以看看:Median of Two Sorted Arrays.所以我們應該要更加註重排序演算法的原理。