题目描述
给你链表的头结点 head
,请将其按 升序 排列并返回 排序后的链表 。
示例 1:
输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2:
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3:
输入:head = []
输出:[]
提示:
- 链表中节点的数目在范围
[0, 5 * 104]
内 -105 <= Node.val <= 105
**进阶:**你可以在 O(n log n)
时间复杂度和常数级空间复杂度下,对链表进行排序吗?
解答
/**
* 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* sortList1(ListNode* head) {
// 转存数组
vector<int> temp;
while(head != nullptr)
{
temp.push_back(head->val);
head = head->next;
}
sort(temp.begin(), temp.end());
ListNode *res = new ListNode(-1);
ListNode *node = res;
for(const int & n : temp)
{
node->next = new ListNode(n);
node = node->next;
}
return res->next;
}
// 方法二:归并排序(递归法)
ListNode* sortList(ListNode* head) {
// 两两归并
// 找到当前链表中点,并从中点断开链表
// 用快慢指针fast和slow,奇数个节点找到中点,偶数个节点找到中心左边的节点(所以fast先走一步)
// 找到重点slow后执行slow->next = nullptr,将链表切断
// 递归分割
if(head == nullptr || head->next == nullptr)
{
return head;
}
// 之所以fast要比slow多一步,是因为后面要用slow->next分割
ListNode *fast = head->next, *slow = head;
while(fast != nullptr && fast->next != nullptr)
{
slow = slow->next;
fast = fast->next->next;
}
// 后一半元素
ListNode *tmp = slow->next;
slow->next = nullptr;
ListNode *left = sortList(head);
ListNode *right = sortList(tmp);
ListNode *h = new ListNode(0);
ListNode *res = h;
// 归并
while(left && right)
{
if(left->val < right->val)
{
h->next = left;
left = left->next;
}
else
{
h->next = right;
right = right->next;
}
h = h->next;
}
h->next = left != nullptr ? left : right;
return res->next;
}
};