题目描述
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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 <= 104
- 0 <= lists[i].length <= 500
- -104 <= lists[i][j] <= 104
- lists[i] 按 升序 排列
- lists[i].length 的总和不超过 104
代码及注释
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
// mergeKLists 函数用于合并 K 个有序链表
func mergeKLists(lists []*ListNode) *ListNode {
// 获取链表列表的长度
length := len(lists)
// 如果链表列表为空,直接返回 nil
if length == 0 {
return nil
}
// 如果链表列表只有一个链表,直接返回该链表
if length == 1 {
return lists[0]
}
// 递归地合并链表列表的前一半和后一半
l := mergeKLists(lists[:length / 2])
r := mergeKLists(lists[length / 2:])
// 合并两个有序链表
return merge(l, r)
}
// merge 函数用于合并两个有序链表
func merge(l1, l2 *ListNode) *ListNode {
// 使用哑节点简化代码
dummy := &ListNode{}
pre := dummy
// 循环比较两个链表的节点,并将较小的节点连接到新链表中
for l1 != nil && l2 != nil {
if l1.Val > l2.Val {
pre.Next = l2
l2 = l2.Next
} else {
pre.Next = l1
l1 = l1.Next
}
pre = pre.Next
}
// 将剩余的节点连接到新链表的末尾
if l1 != nil {
pre.Next = l1
} else {
pre.Next = l2
}
// 返回合并后的链表
return dummy.Next
}
代码解释
使用了分治法的思想来解决合并 K 个有序链表的问题。这里的分治法是递归地将 K 个链表分成两部分,并合并它们。
-
mergeKLists 函数:
- length := len(lists):获取链表列表的长度。
- if length == 0:如果链表列表为空,直接返回
nil
。 - if length == 1:如果链表列表只有一个链表,直接返回该链表。
- l := mergeKLists(lists[:length / 2]) 和 r := mergeKLists(lists[length / 2:]):递归地合并链表列表的前一半和后一半。
- return merge(l, r):合并两个有序链表。
-
merge 函数:
- dummy := &ListNode{} 和 pre := dummy:使用哑节点简化代码,并初始化前一个节点为哑节点。
- for l1 != nil && l2 != nil:循环比较两个链表的当前节点的值,并将较小的节点连接到新链表中。
- if l1 != nil 和 if l2 != nil:将剩余的节点连接到新链表的末尾。
这种方法的时间复杂度是 O(nlogk),其中 (n) 是所有链表中的节点总数,k 是链表的数量。