leetcode 力扣 148 排序链表

84 阅读1分钟

归并排序

注意题目要求是O(nlogn) 时间复杂度和常数级空间复杂度下,对链表进行排序,所以只能对链表进行原地归并排序

算法思路
1、拆分。使用快慢指针,递归地把链表分成两半
2、合并。一边比较大小,一边把每个节点连接起来

合并是难点,可以使用三个指针
h1 左链表指针
h2 右链表指针
pre 前置指针,用于连接下一个节点

因为每比较一次,h1或者h2都会往右移动,总有一个指针先到达null,所以需要把剩下的节点连上: pre.next = h1 == null ? h2 : h1;

lc148_1.jpeg

lc148_2.jpeg

lc148_3.jpeg

lc148_4.jpeg

lc148_5.jpeg

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