题目
- 题号:148
- 难度:中等
- https://leetcode-cn.com/problems/sort-list/
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
进阶:你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
示例
输入:head = [-1,5,3,4,0]输出:[-1,0,3,4,5]
实现
思路1 归并排序
归并排序可以采用自顶向上或者是自顶向下。由于题目要求常数级空间复杂度,所以这里采用自底向上的方法。
- 首先将链表分割成长度为subLen的子链表(初始subLen=1),然后相邻两个子链表进行有序链表的合并(如第21题“合并两个有序链表”),这样就会得到若干个长度为subLen*2的有序子链表。
- 将subLen的值加倍然后重复上述循环,直到有序子链表的长度大于等于链表总长度,最终得到的就是排序好的链表。
/*** 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 {public:ListNode* sortList(ListNode* head) {if (head == nullptr) {return head;}// 1. 首先统计链表长度int length = 0;ListNode* node = head;while (node != nullptr) {length++;node = node->next;}// 2. 引入哨兵节点ListNode* dummyHead = new ListNode(0, head);// 3. 每次将链表拆分成若干个长度为subLen,两两归并for (int subLen = 1; subLen < length; subLen <<= 1) {// curr用来记录链表隔断的位置ListNode* prev = dummyHead, *curr = dummyHead->next;// 开始拆分整个链表while (curr != nullptr) {ListNode* head1 = curr; //第1个长度为subLen的链表头// 3.1 先拆分第1个长度为subLen的链表for (int i = 1; i < subLen && curr->next != nullptr; i++) {curr = curr->next;} // 找到第1个链表的尾部ListNode* head2 = curr->next; // 第2个链表的头,即链表1尾部的下一个节点curr->next = nullptr; // 断开第1个链表和第2个链表的连接curr = head2;// 3.2 再拆分第2个长度为subLen的链表for (int i = 1; i < subLen && curr != nullptr && curr->next != nullptr; i++) {curr = curr->next;} // 找到第2个链表的尾部// 断开第2个链表后面的连接ListNode* next = nullptr;if (curr != nullptr) {next = curr->next; // 用来记录两个链表的结束位置curr->next = nullptr;}// 3.3 合并前面拆分得到的两个subLen长度的有序链表ListNode* merged = mergeTwoLists(head1, head2);prev->next = merged;// 将prev移动到subLen*2位置后面,以开始下一轮的拆分while (prev->next != nullptr) {prev = prev->next;}curr = next;}}return dummyHead->next;}ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {ListNode* head = new ListNode(-1); // 建立新的头用来保存合并后的链表ListNode* tail = head; // 记录新链表的尾部while(l1 != nullptr && l2 != nullptr) {if(l1->val < l2->val) {tail->next = l1;l1 = l1->next;} else {tail->next = l2;l2 = l2->next;}tail = tail->next;}// 遍历后l1和l2最多只有一个还未被合并完// 直接将链表末尾指向未合并完的链表即可if(l1 == nullptr) {tail->next = l2;} else {tail->next = l1;}return head->next;}};
时间复杂度:. 其中n是链表长度。
空间复杂度:.
