148. 排序链表

自顶向下(递归)

class Solution {
    public ListNode sortList(ListNode head) {
        return sortList(head, null);
    }

    public ListNode sortList(ListNode head, ListNode tail){

        /**
         * 自定向下,归并排序
         * 递归终止条件,链表节点数小于2
         * 但是不能用head.next == null来判断只有一个节点,因为中间部分的元素next都不为null
         * 而每个小区间的链表都要是独立的,便于后面的merge合并,因此head还要指向null
         */
        if (head == null){
            return head;
        }

        if (head.next == tail){

            head.next = null;
            return head;
        }

        /**
         * 使用快慢指针找出链表中间节点
         * 快指针每次移动2步,慢指针每次移动1步,当快指针到达链表末尾时,慢指针指向的链表节点即为链表的中点
         */
        ListNode fast = head;
        ListNode slow = head;

        while (fast != tail){

            fast = fast.next;
            slow = slow.next;

            if (fast != tail){
                fast = fast.next;
            }
        }

        /**
         * 尾指针是不包括的,因此list2从mid开始而不是mid.next
         */
        ListNode mid = slow;
        ListNode list1 = sortList(head, mid);
        ListNode list2 = sortList(mid, tail);

        return merge(list1, list2);
    }

    public ListNode merge(ListNode list1, ListNode list2){

        ListNode dummyHead = new ListNode();
        ListNode cur = dummyHead;
        ListNode cur1 = list1;
        ListNode cur2 = list2;

        while (cur1 != null && cur2 != null){

            if (cur1.val <= cur2.val){

                cur.next = cur1;
                cur1 = cur1.next;
                cur = cur.next;
            }
            else {

                cur.next = cur2;
                cur2 = cur2.next;
                cur = cur.next;
            }
        }

        if (cur1 != null){
            cur.next = cur1;
        }

        if (cur2 != null){
            cur.next = cur2;
        }

        return dummyHead.next;
    }
}

/**
 * 时间复杂度 O(nlogn)
 * 空间复杂度 O(logn)
 */

自底向上

class Solution {
    public ListNode sortList(ListNode head) {

        if (head == null || head.next == null){
            return head;
        }

        int length = 0;
        ListNode cur = head;

        /**
         * 遍历链表,获取长度
         */
        while (cur != null){

            length++;
            cur = cur.next;
        }

        ListNode dummyHead = new ListNode(0, head);

        /**
         * 第一层循环,小区间长度size从1开始,每次翻倍
         */
        for (int size = 1; size < length; size *= 2) {

            ListNode prev = dummyHead;
            ListNode curr = dummyHead.next;

            /**
             * 第二层循环,从第一个节点开始,每次遍历邻近的两个长度为size的小区间
             * 找到这两个小区间的头节点,不要忘记尾节点都要指向null
             */
            while (curr != null){

                ListNode list1 = curr;

                /**
                 * 找到第一个区间的尾节点curr
                 */
                for (int i = 1; i < size && curr.next != null; i++) {
                    curr = curr.next;
                }

                /**
                 * 第二个区间的头节点就是curr.next
                 */
                ListNode list2 = curr.next;
                curr.next = null;
                curr = list2;

                /**
                 * 此处curr可能为null,需要判断一下
                 */
                for (int i = 1; i < size && curr != null && curr.next != null; i++) {
                    curr = curr.next;
                }

                ListNode next = null;

                /**
                 * 因为curr可能为null,所以要单独判断
                 */
                if (curr != null){

                    next = curr.next;
                    curr.next = null;
                }

                /**
                 * 将这两个区间合并后,放在prev后,然后prev后移到第二个区间的尾节点
                 */
                prev.next = merge(list1, list2);

                while (prev.next != null){
                    prev = prev.next;
                }

                curr = next;
            }
        }

        return dummyHead.next;
    }

    public ListNode merge(ListNode list1, ListNode list2){

        ListNode dummyHead = new ListNode();
        ListNode cur = dummyHead;

        while (list1 != null && list2 !=null){

            if (list1.val <= list2.val){

                cur.next = list1;
                list1 = list1.next;
            }
            else {

                cur.next = list2;
                list2 = list2.next;
            }

            cur = cur.next;
        }

        cur.next = list1 == null ? list2 : list1;

        return dummyHead.next;
    }
}

/**
 * 时间复杂度 O(nlogn)
 * 空间复杂度 O(1)
 */

https://leetcode-cn.com/problems/sort-list/

posted @ 2021-12-19 14:23  振袖秋枫问红叶  阅读(27)  评论(0)    收藏  举报