返回

路飞通关 LeetCode 23:合并 K 个升序链表,四两拨千斤的合并术

前端

在算法的世界里,链表是一种常见的数据结构,它由一系列节点组成,每个节点包含一个值和指向下一个节点的指针。LeetCode 23 题正是围绕链表合并展开,要求我们把 K 个已经按升序排列的链表合并成一个升序链表。

乍一看,合并链表似乎是一项繁琐的任务,但别担心!路飞将为你揭秘多路归并算法的奥秘,让你轻松搞定这个难题。

多路归并算法

多路归并算法是合并多个有序序列的经典算法。其核心思想是,将序列逐一对半分,然后依次合并,直到所有序列都合并为一个。

在我们的链表合并问题中,我们可以将 K 个链表看作 K 个有序序列。算法步骤如下:

  1. 递归分治: 将 K 个链表分成两组,每一组包含 K/2 个链表。对每组链表递归地应用多路归并算法。
  2. 合并两组: 将分治后得到的两组有序链表合并为一个有序链表。
  3. 重复步骤 1 和 2: 继续递归分治和合并,直到所有链表都被合并为一个。

代码实现

有了多路归并算法的指导,我们就可以用代码来实现链表合并。以 Python 为例,代码如下:

def mergeKLists(lists):
    """
    :type lists: List[ListNode]
    :rtype: ListNode
    """
    if not lists:
        return None

    # 递归基准条件:只有一个链表时,直接返回
    if len(lists) == 1:
        return lists[0]

    # 将链表分成两组
    mid = len(lists) // 2
    left = mergeKLists(lists[:mid])
    right = mergeKLists(lists[mid:])

    # 合并两组链表
    return mergeTwoLists(left, right)


def mergeTwoLists(l1, l2):
    """
    合并两个有序链表
    """
    dummy = ListNode(0)
    curr = dummy

    while l1 and l2:
        if l1.val < l2.val:
            curr.next = l1
            l1 = l1.next
        else:
            curr.next = l2
            l2 = l2.next

        curr = curr.next

    if l1:
        curr.next = l1
    if l2:
        curr.next = l2

    return dummy.next

LeetCode 原题示例

LeetCode 23 给出了一个包含四个升序链表的示例,如下:

[
  1->4->5,
  1->3->4,
  2->6
]

按照多路归并算法的步骤,我们将这些链表合并为一个升序链表:

  1. 将链表分成两组:

    • 第 1 组:1->4->5, 1->3->4
    • 第 2 组:2->6
  2. 分别合并两组:

    • 第 1 组:1->3->4->4->5
    • 第 2 组:2->6
  3. 合并两组:

    • 1->3->4->4->5, 2->6
    • 最终合并后的升序链表:1->2->3->4->4->5->6

总结

通过这篇文章,你已经了解了如何使用多路归并算法合并 K 个升序链表。掌握了这种技术,你将能够轻松应对 LeetCode 23 题和其他类似的链表合并问题。

记住,算法的本质在于分而治之,将复杂问题分解成更小的子问题,逐步解决。多路归并算法正是这种思想的完美体现。

希望这篇文章对你有所帮助。如果你有其他问题或建议,欢迎随时留言。

致谢

感谢「2022首次更文挑战」活动的鼓励,让我有动力持续创作优质文章。期待未来与你分享更多精彩内容!