1. 程式人生 >實用技巧 >其它 >排序連結串列(歸併排序,迭代)

排序連結串列(歸併排序,迭代)


1 題目描述

給你連結串列的頭結點 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 * 10 ^ 4] 內
  • -10 ^ 5 <= Node.val <= 10 ^ 5

2 解題(Java)

題目解析

  1. 最適合連結串列的排序演算法是歸併排序。如果採用自頂向下的遞迴實現,則空間複雜度為O(log n),如果要達到O(1)的空間複雜度,則需要使用自底向上的實現方式;
  2. 首先求得連結串列的長度length,然後將連結串列拆分成子連結串列進行合併;
  3. 用subLength表示每次需要排序的子連結串列的長度,初始subLength=1;
  4. 每次將連結串列拆分成若干個長度為subLength的子連結串列(最後一個子連結串列的長度可以小於subLength),按照每兩個子連結串列一組進行合併,合併後即可得到若干個長度為subLength * 2的有序子連結串列(最後一個子連結串列的長度可以小於subLength * 2);
  5. 將subLength的值加倍,重複4,對更長的有序子連結串列進行合併操作,直到有序子連結串列的長度大於或等於length,整個連結串列排序完畢;

程式碼

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
        int length = 0;
        ListNode node = head;
        while (node != null) {
            node = node.next;
            length++;
        }
        ListNode dummyHead = new ListNode(0, head);
        for (int subLength = 1; subLength < length; subLength <<= 1) {
            ListNode prev = dummyHead, curr = dummyHead.next;
            while (curr != null) {
                ListNode head1 = curr;
                for (int i=1; i<subLength && curr.next != null; i++) {
                    curr = curr.next;
                }
                ListNode head2 = curr.next;
                curr.next = null;
                curr = head2;
                for (int i = 1; i < subLength && curr != null && curr.next != null; i++) {
                    curr = curr.next;
                }
                ListNode next = null;
                if (curr != null) {
                    next = curr.next;
                    curr.next = null;
                }
                ListNode merged = merge(head1, head2);
                prev.next = merged;
                while (prev.next != null) {
                    prev = prev.next;
                }
                curr = next;
            }
        }
        return dummyHead.next;
    }

    public ListNode merge(ListNode head1, ListNode head2) {
        ListNode dummyHead = new ListNode();
        ListNode temp = dummyHead;
        while (head1 != null && head2 != null) {
            if (head1.val <= head2.val) {
                temp.next = head1;
                head1 = head1.next;
            } else {
                temp.next = head2;
                head2 = head2.next;
            }
            temp = temp.next;
        }
        temp.next = head1 == null ? head2 : head1;
        return dummyHead.next;
    }
}

3 複雜性分析

  • 時間複雜度O(nlogn):其中 n 是連結串列的長度;
  • 空間複雜度O(1)

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/sort-list