leetcode:148. 排序链表
题目
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
示例 1:![[中等] 148. 排序链表 - 图1](/uploads/projects/liangduo-rjrcs@ggu4wq/f46d6a3e6c91dfe26db849aeb0f5d0f2.jpeg)
输入:head = [4,2,1,3]输出:[1,2,3,4]
示例 2:![[中等] 148. 排序链表 - 图2](/uploads/projects/liangduo-rjrcs@ggu4wq/e13a9efb76efa4ae1a140968338aedb0.jpeg)
输入:head = [-1,5,3,4,0]输出:[-1,0,3,4,5]
示例 3:
输入:head = []输出:[]
解答 & 代码
解法一:自顶向下归并排序(递归)
- 定位到链表中间节点 mid,将链表拆分成左、右两个子链表
- 分别递归排序左子链表、右子链表
将排序后的左、右子链表合并
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/class Solution {private:// 寻找链表中间节点并返回ListNode* findMidNode(ListNode* head){// 注意这里快、慢指针都从虚拟头节点开始遍历,这样偶数节点链表定位到中间节点,奇数节点// 链表则定位到第一个中间节点,这样得到的中间节点就可以作为左子节点的最后一个节点。// 而如果从 head 开始遍历,奇数节点链表会定位到第二个中间节点,就只能得到右子链表的起点ListNode* dummyHead = new ListNode(0, head);ListNode* fast = dummyHead;ListNode* slow = dummyHead;while(fast != nullptr && fast->next != nullptr){fast = fast->next->next;slow = slow->next;}return slow;}// 合并两个有序链表ListNode* mergeList(ListNode* head1, ListNode* head2){ListNode* dummyHead = new ListNode();ListNode* pre = dummyHead;ListNode* cur1 = head1;ListNode* cur2 = head2;while(cur1 != nullptr && cur2 != nullptr){if(cur1->val < cur2->val){pre->next = cur1;pre = cur1;cur1 = cur1->next;}else{pre->next = cur2;pre = cur2;cur2 = cur2->next;}}if(cur1 != nullptr)pre->next = cur1;if(cur2 != nullptr)pre->next = cur2;return dummyHead->next;}public:// 递归归并排序ListNode* sortList(ListNode* head) {// 递归结束条件:链表为空 or 只有一个节点if(head == nullptr || head->next == nullptr)return head;// 1. 定位到链表中间节点 mid,将链表拆分成左、右两个子链表ListNode* mid = findMidNode(head);ListNode* rightHead = mid->next; // 右子链表的头节点mid->next = nullptr; // 将左子链表的尾部指向 nullptr// 2. 分别递归排序左子链表、右子链表head = sortList(head);rightHead = sortList(rightHead);// 3. 将排序后的左、右子链表合并head = mergeList(head, rightHead);return head;}};
复杂度分析:设链表长为 N
- 时间复杂度 O(N logN):归并排序时间复杂度
- 空间复杂度 O(log N):递归栈空间复杂度
执行结果:
执行结果:通过执行用时:132 ms, 在所有 C++ 提交中击败了 12.01% 的用户内存消耗:59.3 MB, 在所有 C++ 提交中击败了 5.02% 的用户
解法二:自底向上归并排序
[中等] 148. 排序链表
复杂度分析:设链表长为 N
- 时间复杂度 O(N logN):
- 空间复杂度 O(1):
