题目
给你链表的头结点 head
,请将其按 升序 排列并返回 排序后的链表 。
要求时间复杂度为
示例
输入:head = [4,2,1,3] 输出:[1,2,3,4]
输入:head = [-1,5,3,4,0] 输出:[-1,0,3,4,5]
解决方法
使用归并排序。步骤如下:
1. 找到链表的中点,以中点为分界,将链表拆分成两个子链表。寻找链表的中点可以使用快慢指针的做法,快指针每次移动2步,慢指针每次移动1步,当快指针到达链表末尾时,慢指针指向的链表节点即为链表的中点。
2. 对两个子链表分别排序。
3. 合并两个子链表的结果。将两个升序链表合并为一个新的升序链表并返回,合并链表部分的代码实现如下所示:
/**
* 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* mergeTwoLists(ListNode* list1, ListNode* list2) {
if(list1 == nullptr && list2 == nullptr) return nullptr;
if(list1 != nullptr && list2 == nullptr) return list1;
if(list1 == nullptr && list2 != nullptr) return list2;
ListNode* head = new ListNode(0);
if(list1->val > list2->val){
head->next = list2;
list2 = list2->next;
}else{
head->next = list1;
list1 = list1->next;
}
ListNode* cur = head->next;
while(list1 != nullptr && list2 != nullptr){
if(list1->val > list2->val){
cur->next = list2;
list2 = list2->next;
}else{
cur->next = list1;
list1 = list1->next;
}
cur = cur->next;
}
if(list1 != nullptr){
cur->next = list1;
}
if(list2 != nullptr){
cur->next = list2;
}
return head->next;
}
};
代码实现
/**
* 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) {
ListNode* res = sort(head,nullptr);
return res;
}
ListNode* sort(ListNode* head,ListNode* tail){
if (head == nullptr) {
return head;
}
if (head->next == tail) {
head->next = nullptr;
return head;
}
ListNode* slow = head, *fast = head;
while(fast != tail && fast->next != tail){
fast = fast->next->next;
slow = slow->next;
}
ListNode* mid = slow;
ListNode* list1 = sort(head, mid);
ListNode* list2 = sort(mid, tail);
ListNode* res = merge(list1, list2);
return res;
}
ListNode* merge(ListNode* list1, ListNode* list2) {
if(list1 == nullptr && list2 == nullptr) return nullptr;
if(list1 != nullptr && list2 == nullptr) return list1;
if(list1 == nullptr && list2 != nullptr) return list2;
ListNode* head = new ListNode(0);
if(list1->val > list2->val){
head->next = list2;
list2 = list2->next;
}else{
head->next = list1;
list1 = list1->next;
}
ListNode* cur = head->next;
while(list1 != nullptr && list2 != nullptr){
if(list1->val > list2->val){
cur->next = list2;
list2 = list2->next;
}else{
cur->next = list1;
list1 = list1->next;
}
cur = cur->next;
}
if(list1 != nullptr){
cur->next = list1;
}
if(list2 != nullptr){
cur->next = list2;
}
return head->next;
}
};
进阶:非递归解法
采用递归解法时,需要开栈,空间复杂度为.当需要常数级的空间复杂度时,需要将递归解法转化为非递归解法。在这种情况下,需要首先求出链表的长度,然后再将大链表拆分成子链表进行合并。具体步骤如下所示:
1. 用subLength 表示每次需要排序的子链表的长度,初始时 subLength=1。
2. 每次将链表拆分成若干个长度为 subLength 的子链表(最后一个子链表的长度可以小于 subLength),按照每两个子链表一组进行合并,合并后即可得到若干个长度为 subLength×2 的有序子链表(最后一个子链表的长度可以小于 subLength×2)。
3. 将 subLength 的值乘2,重复第 2 步,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于 length,整个链表排序完毕。
更详细的说明见代码注释:
/**
* 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;
}
int length = 0;
ListNode* node = head;
while (node != nullptr) {
length++;
node = node->next;
}
ListNode* dummyHead = new ListNode(0, head);
//每次将链表拆分成若干个长度为 subLength 的子链表,初始值为1
for (int subLength = 1; subLength < length; subLength = subLength*2) {
ListNode* prev = dummyHead, *curr = dummyHead->next;
while (curr != nullptr) { //对整个大链表两个两个进行合并,每个循环代表合并两个子链表。
ListNode* head1 = curr;
//找到第一个子链表的末尾
for (int i = 1; i < subLength && curr->next != nullptr; i++) {
curr = curr->next;
}
//将第一个子链表的尾巴断开
ListNode* head2 = curr->next;
curr->next = nullptr;
curr = head2;
//找到第二个子链表的末尾
for (int i = 1; i < subLength && curr != nullptr && curr->next != nullptr; i++) {
curr = curr->next;
}
//将第二个子链表的尾巴断开
ListNode* next = nullptr;
if (curr != nullptr) {
next = curr->next; //保存断开位置的下一个节点。即这两个子链表合并结束后,下两个子链表的开头。
curr->next = nullptr;
}
//合并第一个第二个子链表
ListNode* merged = merge(head1, head2);
prev->next = merged;
while (prev->next != nullptr) {
prev = prev->next;
}
curr = next; //开始对后面的子链表进行合并
}
}
return dummyHead->next;
}
ListNode* merge(ListNode* list1, ListNode* list2) {
if(list1 == nullptr && list2 == nullptr) return nullptr;
if(list1 != nullptr && list2 == nullptr) return list1;
if(list1 == nullptr && list2 != nullptr) return list2;
ListNode* head = new ListNode(0);
if(list1->val > list2->val){
head->next = list2;
list2 = list2->next;
}else{
head->next = list1;
list1 = list1->next;
}
ListNode* cur = head->next;
while(list1 != nullptr && list2 != nullptr){
if(list1->val > list2->val){
cur->next = list2;
list2 = list2->next;
}else{
cur->next = list1;
list1 = list1->next;
}
cur = cur->next;
}
if(list1 != nullptr){
cur->next = list1;
}
if(list2 != nullptr){
cur->next = list2;
}
return head->next;
}
};