0%

leetcode-148

Sort List

O(nlog n) time and O(1) space

分析题意

由于nlogn的时间复杂度,很自然想到归并排序。归并排序可以自顶向下进行归并,也可以自底向上归并。对于数组来说,自顶向下的归并排序时间复杂度nlogn,空间复杂度为n长度的辅助数组和logn深度的递归深度(n+logn),对于自底向上的归并排序,时间复杂度相同,空间复杂度去除了logn的递归深度栈。而对于链表的归并排序,时间复杂度相同,而由于链表不需要额外的辅助数组,所以自顶向下的空间复杂度为logn,自底向上的空间复杂度为O(1)。所以选择自底向上的归并排序。

代码实现

  • 自顶向下的归并排序
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    /**
    * Definition for singly-linked list.
    * public class ListNode {
    * int val;
    * ListNode next;
    * ListNode(int x) { val = x; }
    * }
    */
    class Solution {
    public ListNode sortList(ListNode head) {
    if (head == null || head.next == null) return head;
    ListNode slow = head;
    ListNode fast = head.next;
    while (fast != null && fast.next != null) {
    slow = slow.next;
    fast = fast.next.next;
    }
    ListNode mid = slow.next;
    slow.next = null;
    return merge(sortList(head), sortList(mid));
    }

    private ListNode merge(ListNode l1, ListNode l2) {
    ListNode dummyNode = new ListNode(0);
    ListNode tail = dummyNode;

    while (l1 != null && l2 != null) {
    if (l1.val > l2.val) {
    ListNode temp = l1;
    l1 = l2;
    l2 = temp;
    }
    tail.next = l1;
    l1 = l1.next;
    tail = tail.next;
    }
    tail.next = (l1 == null) ? l2 : l1;
    return dummyNode.next;
    }
    }
  • 自底向上的归并排序
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    /**
    * Definition for singly-linked list.
    * public class ListNode {
    * int val;
    * ListNode next;
    * ListNode(int x) { val = x; }
    * }
    */
    class Solution {
    public ListNode sortList(ListNode head) {
    if (head == null || head.next == null) return head;
    int length = 0;
    for (ListNode l = head; l != null; l = l.next) length++;

    ListNode dummyNode = new ListNode(0);
    dummyNode.next = head;
    ListNode l;
    ListNode r;
    ListNode tail;
    for (int size = 1; size < length; size *= 2) {
    ListNode cur = dummyNode.next;
    tail = dummyNode;
    while (cur != null) {
    l = cur;
    r = split(l, size);
    cur = split(r, size);
    Pair p = merge(l, r);
    tail.next = p.first;
    tail = p.second;
    }
    }
    return dummyNode.next;
    }

    private ListNode split(ListNode head, int n) {
    while (--n > 0 && head != null) {
    head = head.next;
    }
    ListNode rest = (head != null) ? head.next : null;
    if (head != null) head.next = null;
    return rest;
    }

    private Pair merge(ListNode l1, ListNode l2) {
    ListNode dummyNode = new ListNode(0);
    ListNode tail = dummyNode;
    while (l1 != null && l2 != null) {
    if (l1.val > l2.val) {
    ListNode temp = l1;
    l1 = l2;
    l2 = temp;
    }
    tail.next = l1;
    l1 = l1.next;
    tail = tail.next;
    }
    tail.next = (l1 == null) ? l2 : l1;
    while (tail.next != null) tail = tail.next;
    return new Pair(dummyNode.next, tail);
    }

    private class Pair {
    ListNode first;
    ListNode second;
    Pair(ListNode f, ListNode s) {first = f; second = s;}
    }
    }