链表--排序链表(leetcode 148

题目要求

在 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;
    }

}

猜你喜欢

转载自www.cnblogs.com/swifthao/p/13202315.html