跳过正文
  1. leetcode 题解/

148_排序链表

·388 字·2 分钟

类型:链表

    1. 排序链表 💛 ⭐

    https://leetcode-cn.com/problems/sort-list/

    ❓ 给定一个链表,将其升序排列后返回。

    💡 插入排序

    从前往后找插入点。

    如果是数组的插入排序,则数组的前面部分是有序序列,后面的元素插入到前面后,插入位置后面的元素都往后移动一位。

    对于链表来说,结点插入不需要挨个地挪位置,因此插入的时间复杂度是 O(1),但是每查找一个插入位置都需要 O(n),所以总的时间复杂度仍然达到了 O(n^2)。

    由于单向链表只有指向后一结点的指针,因此我们从前往后地进行插入。同时我们在头部建立虚拟头结点,以方便在头结点之前插入结点。

    class Solution:
        def insertionSortList(self, head: ListNode) -> ListNode:
            if not head:
                return head
    
            dummyHead = ListNode(0)
            dummyHead.next = head
            lastSorted = head
            curr = head.next
    
            while curr:
                if lastSorted.val <= curr.val:
                    lastSorted = lastSorted.next
                else:
                    prev = dummyHead
                    while prev.next.val <= curr.val:
                        prev = prev.next
                    lastSorted.next = curr.next
                    curr.next = prev.next
                    prev.next = curr
                curr = lastSorted.next
    
            return dummyHead.next

    时间复杂度:O(n^2),空间复杂度:O(1)

    💡 归并排序(自顶向下)

    过程如下:

    • 找到链表的中点,以中点为分界,将链表拆分成两个子链表。可以使用快慢指针。
    • 对两个子链表分别排序。
    • 将两个排序后的子链表合并。
    class Solution:
        def sortList(self, head: ListNode) -> ListNode:
            def sortFunc(head: ListNode, tail: ListNode) -> ListNode:
                if not head:
                    return head
                if head.next == tail:
                    head.next = None
                    return head
                slow = fast = head
                while fast != tail:
                    slow = slow.next
                    fast = fast.next
                    if fast != tail:
                        fast = fast.next
                mid = slow
                return merge(sortFunc(head, mid), sortFunc(mid, tail))
    
            def merge(head1: ListNode, head2: ListNode) -> ListNode:
                dummyHead = ListNode(0)
                temp, temp1, temp2 = dummyHead, head1, head2
                while temp1 and temp2:
                    if temp1.val <= temp2.val:
                        temp.next = temp1
                        temp1 = temp1.next
                    else:
                        temp.next = temp2
                        temp2 = temp2.next
                    temp = temp.next
                if temp1:
                    temp.next = temp1
                elif temp2:
                    temp.next = temp2
                return dummyHead.next
    
            return sortFunc(head, None)

    时间复杂度:O(NlogN),空间复杂度:O(logN)

    💡 归并排序(自底向上)

    先计算链表长度 length。

    然后

    • 用 subLength 表示每次需要排序的子链表的长度,初始时 subLength=1。
    • 每次将链表拆分成若干个长度为 subLength 的子链表(最后一个子链表的长度可以小于 subLength),按照每两个子链表一组进行合并,合并后即可得到若干个长度为 subLength×2 的有序子链表(最后一个子链表的长度可以小于 subLength×2)。
    • 将 subLength 的值加倍,重复第 2 步,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于 length,整个链表排序完毕。
    class Solution:
        def sortList(self, head: ListNode) -> ListNode:
            def merge(head1: ListNode, head2: ListNode) -> ListNode:
                dummyHead = ListNode(0)
                temp, temp1, temp2 = dummyHead, head1, head2
                while temp1 and temp2:
                    if temp1.val <= temp2.val:
                        temp.next = temp1
                        temp1 = temp1.next
                    else:
                        temp.next = temp2
                        temp2 = temp2.next
                    temp = temp.next
                if temp1:
                    temp.next = temp1
                elif temp2:
                    temp.next = temp2
                return dummyHead.next
    
            if not head:
                return head
    
            length = 0
            node = head
            while node:
                length += 1
                node = node.next
    
            dummyHead = ListNode(0, head)
            subLength = 1
            while subLength < length:
                prev, curr = dummyHead, dummyHead.next
                while curr:
                    head1 = curr
                    for i in range(1, subLength):
                        if curr.next:
                            curr = curr.next
                        else:
                            break
                    head2 = curr.next
                    curr.next = None
                    curr = head2
                    for i in range(1, subLength):
                        if curr and curr.next:
                            curr = curr.next
                        else:
                            break
    
                    succ = None
                    if curr:
                        succ = curr.next
                        curr.next = None
    
                    merged = merge(head1, head2)
                    prev.next = merged
                    while prev.next:
                        prev = prev.next
                    curr = succ
                subLength <<= 1
    
            return dummyHead.next

    时间复杂度:O(NlogN),空间复杂度:O(1)