归并排序
注意题目要求是O(nlogn) 时间复杂度和常数级空间复杂度下,对链表进行排序,所以只能对链表进行原地归并排序
算法思路
1、拆分。使用快慢指针,递归地把链表分成两半
2、合并。一边比较大小,一边把每个节点连接起来
合并是难点,可以使用三个指针
h1 左链表指针
h2 右链表指针
pre 前置指针,用于连接下一个节点
因为每比较一次,h1或者h2都会往右移动,总有一个指针先到达null,所以需要把剩下的节点连上:
pre.next = h1 == null ? h2 : h1;
public ListNode sortList(ListNode head) {
// 1. 递归地把链表分成left和right
// 2.比较left和right的大小,然后合并
if (head == null || head.next == null) {
return head;
}
ListNode slow = head, fast = head.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode rightHead = slow.next;
slow.next = null;
ListNode left = sortList(head);
ListNode right = sortList(rightHead);
return merge(left, right);
}
private ListNode merge(ListNode h1, ListNode h2) {
ListNode dummy = new ListNode(-1);
ListNode pre = dummy;
while (h1 != null && h2 != null) {
if (h1.val < h2.val) {
pre.next = h1;
h1 = h1.next;
} else {
pre.next = h2;
h2 = h2.next;
}
pre = pre.next;
}
pre.next = h1 == null ? h2 : h1;
return dummy.next;
}