1. 程式人生 > 其它 >Medium | LeetCode 148. 排序連結串列 | 歸併排序(遞迴)

Medium | LeetCode 148. 排序連結串列 | 歸併排序(遞迴)

148. 排序連結串列

難度中等1181

給你連結串列的頭結點 head ,請將其按 升序 排列並返回 排序後的連結串列

進階:

  • 你可以在 O(n log n) 時間複雜度和常數級空間複雜度下,對連結串列進行排序嗎?

示例 1:

輸入:head = [4,2,1,3]
輸出:[1,2,3,4]

示例 2:

輸入:head = [-1,5,3,4,0]
輸出:[-1,0,3,4,5]

示例 3:

輸入:head = []
輸出:[]

提示:

  • 連結串列中節點的數目在範圍 [0, 5 * 104]
  • -105 <= Node.val <= 105

解題思路

方法一: 歸併排序(遞迴)

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

/**
 * 排序[head, tail)這部分的連結串列, 這是一個左閉右開的連結串列
 * @param head 連結串列頭部
 * @param tail 連結串列尾部
 * @return 排序後的連結串列
 */
public ListNode sortList(ListNode head, ListNode tail) {
    // 空連結串列直接返回
    if (head == null) {
        return head;
    }
    // 只有一個節點
    if (head.next == tail) {
        // 將next指標置位空
        head.next = null;
        return head;
    }
    // 快慢指標法找到連結串列的中間節點
    ListNode slow = head, fast = head;
    while (fast != tail) {
        // 慢指標每次走一步
        slow = slow.next;
        // 快指標每次走兩步
        fast = fast.next;
        if (fast != tail) {
            fast = fast.next;
        }
    }
    // 將連結串列切成兩塊分別遞迴進行歸併排序
    ListNode mid = slow;
    ListNode list1 = sortList(head, mid);
    ListNode list2 = sortList(mid, tail);
    return merge(list1, list2);
}

public ListNode merge(ListNode la, ListNode lb) {
    ListNode dumpHead = new ListNode();
    ListNode pre = dumpHead;
    ListNode pa = la, pb = lb;
    while (pa != null && pb != null) {
        if (pa.val <= pb.val) {
            pre.next = pa;
            pa = pa.next;
        } else {
            pre.next = pb;
            pb = pb.next;
        }
        pre = pre.next;
    }
    pre.next = (pa == null) ? pb : pa;
    return dumpHead.next;
}