Medium | LeetCode 148. 排序链表 | 归并排序(递归)
148. 排序链表
给你链表的头结点 head
,请将其按 升序 排列并返回 排序后的链表 。
进阶:
- 你可以在
O(n log n)
时间复杂度和常数级空间复杂度下,对链表进行排序吗?
示例 1:
![img](https://assets.leetcode.com/uploads/2020/09/14/sort_list_1.jpg)
输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2:
![img](https://assets.leetcode.com/uploads/2020/09/14/sort_list_2.jpg)
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3:
输入:head = []
输出:[]
提示:
- 链表中节点的数目在范围
[0, 5 * 104]
内 -105 <= Node.val <= 105
解题思路
方法一: 归并排序(递归)
public ListNode sortList(ListNode head) {
return sortList(head, null);
}
/**
* 排序[head, tail)这部分的链表, 这是一个左闭右开的链表
* @param head 链表头部
* @param tail 链表尾部
* @return 排序后的链表
*/
public ListNode sortList(ListNode head, ListNode tail) {
// 空链表直接返回
if (head == null) {
return head;
}
// 只有一个节点
if (head.next == tail) {
// 将next指针置位空
head.next = null;
return head;
}
// 快慢指针法找到链表的中间节点
ListNode slow = head, fast = head;
while (fast != tail) {
// 慢指针每次走一步
slow = slow.next;
// 快指针每次走两步
fast = fast.next;
if (fast != tail) {
fast = fast.next;
}
}
// 将链表切成两块分别递归进行归并排序
ListNode mid = slow;
ListNode list1 = sortList(head, mid);
ListNode list2 = sortList(mid, tail);
return merge(list1, list2);
}
public ListNode merge(ListNode la, ListNode lb) {
ListNode dumpHead = new ListNode();
ListNode pre = dumpHead;
ListNode pa = la, pb = lb;
while (pa != null && pb != null) {
if (pa.val <= pb.val) {
pre.next = pa;
pa = pa.next;
} else {
pre.next = pb;
pb = pb.next;
}
pre = pre.next;
}
pre.next = (pa == null) ? pb : pa;
return dumpHead.next;
}