LeetCode148. Sort List

Analysis

This question requires to sort a LinkedList in O(nlogn) time and O(1) space. We know that all comparison-based sorting alrogithm have the upperbound time complexity of O(nlogn). Thus it is obvious that we are looking for some transformation of one of the following algorithms:

Merge sort, Quick sort, Heap sort.

Considering we are dealing with a LinkedList and can only use O(1) space, we need to think of which one of the above algorithm can be applied to this situation.

Heap sort is apparently not applicable because of its space complexity.

Quick sort is applicable since, we just need to modify the corresponding partition process of quick sort.

A quick sort implmentation is showed as following.

Note that an important difference of this quick sort with a normal array quick sort is that we have to merge the resulting sub-LinkedList.

class Solution {
    public ListNode sortList(ListNode head) {
        // When the LinkedList is null or has a length of 1, no need to sort.
        if (head == null || head.next == null) {
            return head;
        }
        
        return quickSort(head);
    }
    
    private ListNode quickSort(ListNode head) {
        // Base case
        if (head == null || head.next == null) {
            return head;
        }
        
        ListNode fakeSmall = new ListNode(0);
        ListNode small = fakeSmall;
        ListNode fakeEqual = new ListNode(0);
        ListNode equal = fakeEqual;
        ListNode fakeLarge = new ListNode(0);
        ListNode large = fakeLarge;
        
        // use head as pivot
        ListNode curr = head;
        while (curr != null) {
            if (curr.val > head.val) {
                large.next = curr;
                large = large.next;
            } else if (curr.val < head.val) {
                small.next = curr;
                small = small.next;
            } else {
                equal.next = curr;
                equal = equal.next;
            }
            
            curr = curr.next;
        }
        
        small.next = null;
        large.next = null;
        equal.next = null;
        
        return merge(merge(quickSort(fakeLarge.next), quickSort(fakeSmall.next)), fakeEqual.next);
    }

Merge sort is also applicable, we need to change the process of finding middle point and merge. The merge is just the same as Merge 2 sorted LinkedList.

A merge sort implementation is showed as following:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
        // When the LinkedList is null or has a length of 1, no need to sort.
        if (head == null || head.next == null) {
            return head;
        }
        
        return mergeSort(head);
    }
    
    private ListNode mergeSort(ListNode head) {
        /**
         * Using merge sort to sort the 2 LinkedList recursively.
         */
        if (head.next == null) {
            return head;
        }
        
        // Get the middle point of the LinkedList
        ListNode middle = findMiddle(head);
        
        // Sort the first half
        ListNode left = mergeSort(head);
        
        // Sort the second half
        ListNode right = mergeSort(middle);
        
        return merge(left, right);
    }
    
    private ListNode merge(ListNode left, ListNode right) {
        // Merge 2 sorted LinkedList
        ListNode dummy = new ListNode(0);
        ListNode head = dummy;
        while (left != null && right != null) {
            if (left.val <= right.val) {
                head.next = left;
                left = left.next;
            } else {
                head.next = right;
                right = right.next;
            }
            head = head.next;
        }
        
        if (left != null) {
            head.next = left;
        }
        if (right != null) {
            head.next = right;
        }
        
        return dummy.next;
    }
    
    private ListNode findMiddle(ListNode head) {
        /**
         * Find the middle point of a linked list
         * And split the original LinkedList into 2 separated List by removing
         * the next pointer in the middle.
         */
        ListNode fast = head;
        ListNode slow = head;
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        
        ListNode ret = slow.next;
        slow.next = null;
        return ret;
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容