题目要求
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
解析
以下解析来自于https://www.cnblogs.com/grandyang/p/4249905.html
常见排序方法有很多,插入排序,选择排序,堆排序,快速排序,冒泡排序,归并排序,桶排序等等。。它们的时间复杂度不尽相同,而这里题目限定了时间必须为O(nlgn),符合要求只有快速排序,归并排序,堆排序
根据单链表的特点,最适于用归并排序。为啥呢?这是由于链表自身的特点决定的,由于不能通过坐标来直接访问元素,所以快排什么的可能不太容易实现(但是被评论区的大神们打脸,还是可以实现的),堆排序的话,如果让新建结点的话,还是可以考虑的,若只能交换结点,最好还是不要用。而归并排序(又称混合排序)因其可以利用递归来交换数字,天然适合链表这种结构。
所以说,本题 = leetcode 876(找中间结点) + leetcode 21(合并两个有序链表),注意真正实现排序的部分其实是在合并这个部分中。
代码
注意递归的终止条件一定要写对
public class Solution148 {
public ListNode sortList(ListNode head) {
if (head == null || head.next == null){
return head;
}
ListNode fast = head;
ListNode slow = head;
ListNode pre = head;
while (fast != null && fast.next != null) {
pre = slow;
fast = fast.next.next;
slow = slow.next;
}
pre.next = null;
return merge(sortList(head), sortList(slow));
// while (fast.next != null && fast.next.next != null){
// fast = fast.next.next;
// slow = slow.next;
// }
// ListNode newHead = slow.next;
// slow.next = null;
//
// return merge(sortList(head), sortList(newHead));
}
public ListNode merge(ListNode l1, ListNode l2){
ListNode dummy = new ListNode(-1);
ListNode temp = dummy;
while (l1 != null && l2 != null){
if (l1.val < l2.val){
temp.next = l1;
l1 = l1.next;
}else {
temp.next = l2;
l2 = l2.next;
}
temp = temp.next;
}
temp.next = l1 == null ? l2 : l1;
return dummy.next;
}
}