返回

路飞:程序员必刷力扣题:148. 排序合并

前端

算法剖析

148. 排序合并

题目
给你一个头结点为 head 的无环单向表,请把它 原地 排序,并返回重新排序后的头结点。

示例:
示例 1:

输入:head = [4,2,1,3]
输出:[1,2,3,4]

示例 2:

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

提示:

  • 题目保证 无环单向表 的性质。
  • 排序后的单向表 必须原地 排序,即在不创建新节点或使用额外空间的前提下进行排序。

算法实现

方法:归并排序

归并排序是一种经典的分治算法,它可以高效地对一个无序的单向表进行排序。其主要思想是:

  1. 将单向表一分为二,分别对这两个子表进行归并排序。
  2. 将排好序的子表合并起来,得到一个排好序的单向表。

步骤:

  1. 寻找中点: 使用快慢指针法找到单向表中的中点,慢指针每次走一步,快指针每次走两步。这样当快指针走到单向表的末尾时,慢指针刚好走到中点。
  2. 拆分单向表: 在中点处将单向表拆分成两个子表,leftright
  3. 归并排序子表:leftright 子表分别进行归并排序,得到两个排好序的子表。
  4. 合并子表: 将排好序的 leftright 子表合并成一个排好序的单向表。合并过程中,从两个子表中比较取最小的节点,依次组成合并后的单向表。
  5. 返回结果: 返回合并好的单向表作为排好序后的结果。

代码实现(Python)

def sortList(head):
    if not head or not head.next:
        return head

    # 寻找中点
    slow, fast = head, head.next
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next

    # 拆分单向表
    mid = slow.next
    slow.next = None

    # 归并排序子表
    left = sortList(head)
    right = sortList(mid)

    # 合并子表
    return merge(left, right)

def merge(left, right):
    dummy = ListNode(0)
    curr = dummy

    while left and right:
        if left.val < right.val:
            curr.next = left
            left = left.next
        else:
            curr.next = right
            right = right.next
        curr = curr.next

    curr.next = left or right

    return dummy.next

复杂度分析

时间复杂度: O(n log n)
空间复杂度: O(1)

优化技巧

  • 避免不必要复制: 在合并子表时,可以通过指针操作直接修改原单向表,避免创建新的节点。
  • 使用栈而不是显式拆分: 使用栈来存储单向表的拆分点,可以简化拆分和合并的代码。

应用场景

该算法在以下场景中非常有用:

  • 对大型单向表进行 原地 排序。
  • 在内存受限的环境中对数据进行排序。
  • 作为一种通用的排序算法,适用于各种数据结构。

结语

掌握排序合并算法对于程序员来说非常重要。它是一种高效的原地排序算法,在实际应用中有着举足轻重的作用。通过对算法的深入理解和优化,程序员可以在面试和编码实践中游刃有余。