Loading

[LeetCode] 148. Sort List(单链表排序)

Description

Given the head of a linked list, return the list after sorting it in ascending order.
给定单链表的头节点 head,对其升序排序,然后返回该链表。

Follow up

Can you sort the linked list in O(n logn) time and O(1) memory (i.e. constant space)?
你能以 \(O(N\log{N})\) 的时间复杂度和 \(O(1)\) 的空间复杂度解决它吗?

Examples

Example 1

Input: head = [4,2,1,3]
Output: [1,2,3,4]

Example 2

Input: head = [-1,5,3,4,0]
Output: [-1,0,3,4,5]

Example 3

Input: head = []
Output: []

Constraints

  • The number of nodes in the list is in the range [0, 5 * 104].
  • -105 <= Node.val <= 105

Solution

对于单链表来说最合适的排序算法,\(O(N^2)\) 算法里比较适合的是插入排序,\(O(N\log{N})\) 算法里比较适合的是归并排序,本题将他们各自实现一遍,详细的步骤附在代码的注释里。

插入排序版本:

/**
 * Example:
 * var li = ListNode(5)
 * var v = li.`val`
 * Definition for singly-linked list.
 * class ListNode(var `val`: Int) {
 *     var next: ListNode? = null
 * }
 */
class Solution {
    fun sortList(head: ListNode?): ListNode? {
        // 链表为空或只有一个元素,就不管它了,直接返回
        if (head?.next == null) {
            return head
        }
        // 在这里,交换是交换节点本身,所以加入 dummy 节点
        val dummy = ListNode(-1)
        dummy.next = head
        // end 初始为 head,在排序过程中,dummy(不包括,仅为了方便交换) 到 head(包括)之间的所有节点都是有序的
        // 我们要做的,就是把 head 后面的节点不断插入这个有序的区间里。
        var end = head
        // cur -> 当前要处理的节点
        var cur = head.next
        while (cur != null) {
            var p = dummy.next
            var pre: ListNode? = dummy
            // 找到合适的插入位置
            while (p != cur && cur.`val` >= p!!.`val`) {
                p = p.next
                pre = pre?.next
            }

            if (cur === p) {
                // 当前节点是已排序区间内最大的,直接把区间后移
                end = cur
            } else {
                // 插入进合适的位置
                end?.next = cur.next
                cur.next = p
                pre?.next = cur
            }

            // 处理下一个节点
            cur = end?.next
        }

        return dummy.next
    }
}

归并排序版:

/**
 * Example:
 * var li = ListNode(5)
 * var v = li.`val`
 * Definition for singly-linked list.
 * class ListNode(var `val`: Int) {
 *     var next: ListNode? = null
 * }
 */
class Solution {
    fun sortList(head: ListNode?): ListNode? {
        // 如果链表为空或者只有一个节点,不管它了,直接返回
        if (head?.next == null) {
            return head
        }

        // 双指针法找出中间节点
        var fast = head
        var slow = head
        while (fast?.next?.next != null) {
            fast = fast.next?.next
            slow = slow?.next
        }

        // 将链表的前后两部分断开
        fast = slow
        slow = slow?.next
        fast?.next = null

        // 分别对前后两段进行排序
        fast = sortList(head)
        slow = sortList(slow)

        return merge(fast, slow)
    }

    private fun merge(left: ListNode?, right: ListNode?): ListNode? {
        // 特殊情况处理,一边为空就返回另一边
        if (left == null) {
            return right
        }
        if (right == null) {
            return left
        }

        var p = left
        var q = right

        val dummy = ListNode(-1)
        var result: ListNode? = dummy
        while (p != null && q != null) {
            if (p.`val` < q.`val`) {
                result?.next = p
                p = p.next
            } else {
                result?.next = q
                q = q.next
            }
            result = result?.next
        }

        result?.next = p?:q
        return dummy.next
    }
}
posted @ 2020-11-24 10:22  Zhongju.copy()  阅读(81)  评论(0编辑  收藏  举报