LeetCode 23-合并K个升序链表

87 阅读3分钟

题目

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:

输入: lists = [[1,4,5],[1,3,4],[2,6]]
输出: [1,1,2,3,4,4,5,6]
解释: 链表数组如下:
[
  1->4->5,
  1->3->4,
  2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

示例 2:

输入: lists = []
输出: []

示例 3:

输入: lists = [[]]
输出: []

提示:

  • k == lists.length
  • 0 <= k <= 10^4
  • 0 <= lists[i].length <= 500
  • -10^4 <= lists[i][j] <= 10^4
  • lists[i] 按 升序 排列
  • lists[i].length 的总和不超过 10^4

思路

解法一: 顺序合并

顺序合并,第一个和第二个合并后的链表res,再和第三个链表合并,直到合并到第K个,完成最终的所有链表合并。

注意:合并时候的变量赋值。

代码一:顺序合并

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        if len(lists) == 0:
            return
        if len(lists) == 1:
            return lists[0]
        
        res = lists[0]
        for i in range(1, len(lists)):
            res = merge(res, lists[i])
        return res
        

def merge(l1, l2):
    """合并2个链表"""
    if l1 is None or l2 is None:
        return l1 or l2
    head = l1 if l1.val < l2.val else l2
    res = head
    cur1 = l1.next if head == l1 else l2.next
    cur2 = l2 if head == l1 else l1
    while cur1 is not None and cur2 is not None:
        if cur1.val <= cur2.val:
            head.next = cur1
            cur1 = cur1.next
        else:
            head.next = cur2
            cur2 = cur2.next
        head = head.next
    
    # 处理公共长度之外的链表
    if cur1 is not None:
        head.next = cur1
    if cur2 is not None:
        head.next = cur2
    return res

解法二: 分治+合并

分治法,类似于归并排序,将k个链表区分为left,right,直到left和right都只包含一个链表,然后进行链表的整合。

代码二: 分治+合并

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        if len(lists) == 0:
            return
        if len(lists) == 1:
            return lists[0]
        
        return merge(0, len(lists)-1, lists)

def merge(l, r, nodes):
    """分治处理主函数"""
    if l == r:
        return nodes[l]
    
    mid = (l + r) >> 1
    left = merge(l, mid, nodes)
    right = merge(mid+1, r, nodes)
    if left is None or right is None:
        return left or right

    head = left if left.val <= right.val else right
    res = head
    cur1 = left.next if head == left else right.next
    cur2 = left if head == right else right
    while cur1 is not None and cur2 is not None:
        if cur1.val <= cur2.val:
            head.next = cur1
            cur1 = cur1.next
        else:
            head.next = cur2
            cur2 = cur2.next
        head = head.next
    if cur1 is not None:
        head.next = cur1
    if cur2 is not None:
        head.next = cur2
    return res

解法三: 优先队列

利用优先队列,维护当前没被合并元素最前面的一个,K个链表,最多就有K个满足这样的元素,利用优先队列,每次找到当前的最小结点,然后将这个节点移除,将该节点的下一个节点加入优先队列。一直轮询获取当前的最小节点,直到这个优先队列为空,返回结果。

代码三: 优先队列轮询

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next

from queue import PriorityQueue

class Status:
    def __init__(self, val, ptr):
        self.val = val
        self.ptr = ptr
    
    def __lt__(self, other):
        return self.val < other.val


class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        if len(lists) == 0:
            return
        if len(lists) == 1:
            return lists[0]
        
        # Python 优先队列,内部是栈实现,线程安全
        q = PriorityQueue()
        for node in lists:
            if node is not None:
                q.put(Status(node.val, node))
        
        # 设置一个哨兵变量
        head = ListNode(0)
        tail = head
        while q.qsize() > 0:
            # 取到最小的值和节点
            cur = q.get()
            tail.next = cur.ptr
            tail = tail.next
            if cur.ptr.next is not None:
                q.put(Status(cur.ptr.next.val, cur.ptr.next))
        return head.next