leetcode 148. Sort List
Sort a linked list in O(n log n) time using constant space complexity.
Example 1:
Input: 4->2->1->3 Output: 1->2->3->4
Example 2:
Input: -1->5->3->4->0 Output: -1->0->3->4->5
Example 3:
Input: head = [] Output: []
Constraints:
- The number of nodes in the list is in the range
[0, 5 * 104]
. -105 <= Node.val <= 105
题目难度:简单(递归式归并),中等(非递归归并)
题目大意:给一个链表排序,并要求常数空间复杂度$O(1)$,$O(nlogn)时间复杂度$
思路:常用的快排和归并排序,快排在有些情况下的时间复杂度是$(n^2)$,在链表情况下不方便。选择第一个节点为枢纽值。
归并排序时间复杂度是$O(nlogn)$,用递归方法实现的方法,空间复杂度是O(logn)(栈)。所以按照提议应该选择迭代式的归并排序,可以实现$O(1)$空间复杂度(由于是链表,在归并的时候可以不用先new数组作为辅助)。
版本一:递归式的归并排序C++代码:
1 /** 2 * Definition for singly-linked list. 3 * struct ListNode { 4 * int val; 5 * ListNode *next; 6 * ListNode() : val(0), next(nullptr) {} 7 * ListNode(int x) : val(x), next(nullptr) {} 8 * ListNode(int x, ListNode *next) : val(x), next(next) {} 9 * }; 10 */ 11 class Solution { 12 private: 13 //合并两个有序链表 14 ListNode* mergeList(ListNode *front, ListNode *rear) { 15 ListNode *res = new ListNode(0), *tail = res; 16 ListNode *tmp1 = front, *tmp2 = rear; 17 while ((nullptr != tmp1) && (nullptr != tmp2)) { 18 if (tmp1->val <= tmp2->val) { 19 tail->next = tmp1; 20 tail = tmp1; 21 tmp1 = tmp1->next; 22 } else { 23 tail->next = tmp2; 24 tail = tmp2; 25 tmp2 = tmp2->next; 26 } 27 tail->next = NULL; 28 } 29 if (nullptr != tmp1) 30 tail->next = tmp1; 31 else 32 tail->next = tmp2; 33 return res->next; 34 } 35 //找到后一半链表,并返回后一半链表的头指针,同时将前一半链表的尾结点指针指向NULL。 36 ListNode* splitList(ListNode *head) { 37 ListNode *midPrev = head, *fast = head->next; 38 //采用快慢指针的方法找到链表中点 39 while ((nullptr != fast) && (nullptr != fast->next)) { 40 fast = fast->next->next; 41 midPrev = midPrev->next; 42 } 43 ListNode *mid = midPrev->next; 44 midPrev->next = nullptr; 45 return mid; 46 } 47 // void printList(ListNode *head) { 48 // if (nullptr == head) return; 49 // cout << head->val; 50 // ListNode *tmp = head->next; 51 // while (nullptr != tmp) { 52 // cout << "->" << tmp->val; 53 // tmp = tmp->next; 54 // } 55 // cout << endl; 56 // } 57 public: 58 ListNode* sortList(ListNode* head) { 59 if ((head == nullptr) || (head->next == nullptr)) return head; 60 ListNode *rear = splitList(head); //找到后一半链表 61 // printList(head); 62 // printList(rear); 63 ListNode *head1 = sortList(head); //将前一半链表排好序 64 // printList(head1); 65 ListNode *head2 = sortList(rear); //将后一半链表排好序 66 // printList(head2); 67 return mergeList(head1, head2); //合并两个排好序的链表,并返回。 68 } 69 };
版本二:迭代式的归并排序C++代码:
1 class Solution { 2 private: 3 ListNode* split(ListNode *start, int size) { 4 ListNode* midPrev = start; 5 ListNode* end = start->next; 6 for (int index = 1; index < size && (midPrev->next || end->next); ++index) { 7 if (end->next) { 8 end = (end->next->next) ? end->next->next : end->next; 9 } 10 if (midPrev->next) { 11 midPrev = midPrev->next; 12 } 13 } 14 ListNode *mid = midPrev->next; 15 nextSubList = end->next; 16 midPrev->next = nullptr; 17 end->next = nullptr; 18 return mid; 19 } 20 21 //合并两个有序链表 22 void mergeList(ListNode *front, ListNode *rear) { 23 ListNode *res = new ListNode(0), *newTail = res; 24 ListNode *tmp1 = front, *tmp2 = rear; 25 while ((nullptr != tmp1) && (nullptr != tmp2)) { 26 if (tmp1->val <= tmp2->val) { 27 newTail->next = tmp1; 28 newTail = tmp1; 29 tmp1 = tmp1->next; 30 } else { 31 newTail->next = tmp2; 32 newTail = tmp2; 33 tmp2 = tmp2->next; 34 } 35 newTail->next = NULL; 36 } 37 if (nullptr != tmp1) 38 newTail->next = tmp1; 39 else 40 newTail->next = tmp2; 41 while (newTail->next) { 42 newTail = newTail->next; 43 } 44 tail->next = res->next; 45 tail = newTail; 46 } 47 int gCount(ListNode *head) { 48 int cnt = 0; 49 ListNode *tmp = head; 50 while (nullptr != tmp) { 51 ++cnt; 52 tmp = tmp->next; 53 } 54 return cnt; 55 } 56 // void printList(ListNode *head) { 57 // if (nullptr == head) return; 58 // cout << head->val; 59 // ListNode *tmp = head->next; 60 // while (nullptr != tmp) { 61 // cout << "->" << tmp->val; 62 // tmp = tmp->next; 63 // } 64 // cout << endl; 65 // } 66 public: 67 ListNode *tail = new ListNode(); //用于始终指向已排序部分的尾结点 68 ListNode *nextSubList = new ListNode(); //始终指向待排序部分的头结点 69 70 ListNode* sortList(ListNode* head) { 71 if (!head || !head->next) return head; 72 int sz = gCount(head); 73 ListNode *start = head; 74 ListNode *dummyHead = new ListNode(0); 75 for (int size = 1; size < sz; size = size * 2) { 76 tail = dummyHead; 77 while (start) { 78 if (!start->next) { 79 tail->next = start; 80 break; 81 } 82 ListNode *mid = split(start, size); 83 mergeList(start, mid); 84 start = nextSubList; 85 } 86 start = dummyHead->next; 87 } 88 return dummyHead->next; 89 } 90 };
越努力,越幸运