在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
思路:
利用归并的思想,递归地将当前链表分为两段,然后merge,分两段的方法是使用 fast-slow 法,用两个指针,一个每次走两步,一个走一步,知道快的走到了末尾,然后慢的所在位置就是中间位置,这样就分成了两段。merge时,把两段头部节点值比较,用一个 p 指向较小的,且记录第一个节点,然后 两段的头一步一步向后走,p也一直向后走,总是指向较小节点,直至其中一个头为NULL,处理剩下的元素。最后返回记录的头即可
- 知识点1:归并排序的整体思想
- 知识点2:找到一个链表的中间节点的方法
- 知识点3:合并两个已排好序的链表为一个新的有序链表
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
//知识点1:归并排序的整体思想
//知识点2:找到一个链表的中间节点的方法
//知识点3:合并两个已排好序的链表为一个新的有序链表
ListNode* sortList(ListNode* head) {
return mergeSort(head);
}
ListNode* mergeSort(ListNode* node){
if(!node||!node->next)return node;
//快慢指针
ListNode* fast=node;
ListNode* slow=node;
ListNode* breakN=node;//中间结点的前一个结点 即第一段链表的尾结点
while(fast&&fast->next){
fast=fast->next->next;
breakN=slow;
slow=slow->next;
}
breakN->next=nullptr;
ListNode *l1=mergeSort(node);
ListNode* l2=mergeSort(slow);
return merge(l1,l2);
}
ListNode* merge(ListNode* l1,ListNode* l2){
if(l1==nullptr)return l2;
if(l2==nullptr)return l1;
//分情况递归实现
if(l1->val<=l2->val){
l1->next=merge(l1->next,l2);
return l1;
}
else{
l2->next=merge(l2->next,l1);
return l2;
}
}
};