题目如题,但是题目推荐在
O(n log n)时间复杂度和常数级空间复杂度下,对链表进行排序。
=> 归并排序 or 快排
归并和快排都是分治的思想,所以一开始尝试用快排,但是实现到一半发现非常复杂,遂改用分治。
思路
分治是不断递归二分链表,直到成为单个节点,然后再通过合并函数有序合并元素,总结而言: 1.查找中心节点,二分调用自身 2.合并左右二分的链表为有序链表
重点
既然要二分,不可避免要查找链表到中心节点,这里查找中心节点使用的是快慢指针,快指针一次走两格。
踩坑点是:如果链表是偶数个节点,那么快慢指针从同一个起点走,找到的中间节点就会是右半部分的起始节点,导致在链表节点数为偶数时,左右两部分划分不合理。 这里应该让快指针初始化时,多走一步。
实现
/**
* 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* merge(ListNode* list1, ListNode* list2) {
ListNode head;
ListNode *prev = &head;
ListNode *pList1Node = list1, *pList2Node = list2;
while (pList1Node && pList2Node) {
if (pList1Node->val < pList2Node->val) {
prev->next = pList1Node;
pList1Node = pList1Node->next;
}
else {
prev->next = pList2Node;
pList2Node = pList2Node->next;
}
prev = prev->next;
}
if (pList1Node) {
prev->next = pList1Node;
}
if (pList2Node) {
prev->next = pList2Node;
}
return head.next;
}
ListNode* getMidNode(ListNode* head) {
if (!head) { return head; }
ListNode* quick = head->next;
ListNode* mid = head;
while (quick && quick->next) {
mid = mid->next;
quick = quick->next->next;
}
return mid;
}
ListNode* sortList(ListNode* head) {
if (!head || !head->next) { return head; }
ListNode* mid = getMidNode(head);
ListNode* left = head;
ListNode* right = mid->next;
mid->next = nullptr;
ListNode* leftSorted = sortList(left);
ListNode* rightSorted = sortList(right);
return merge(leftSorted, rightSorted);
}
};