Hard
题目描述
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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.length0 <= k <= 10^40 <= lists[i].length <= 500-10^4 <= lists[i][j] <= 10^4lists[i]按升序排列lists[i].length的总和不会超过10^4
解题思路
这是一个经典的分治问题,有三种主要解法:
方法一:逐一合并(暴力法)
依次将每个链表与结果链表合并,时间复杂度较高。
方法二:分治合并(推荐)
采用分治思想,将k个链表两两配对进行合并,类似归并排序的思路。每轮合并后链表数量减半,直到只剩一个链表。这种方法效率最高,是最优解。
方法三:优先队列(堆)
使用最小堆维护每个链表的当前节点,每次取出最小值节点,然后将该节点的下一个节点加入堆中。
分治法是最优解法,其核心思想是:先将相邻的链表两两合并,得到k/2个链表;然后继续两两合并,直到最终合并成一个链表。这样可以最大化利用已有的有序性,避免重复比较。
具体实现中,我们需要实现一个合并两个有序链表的辅助函数,然后在主函数中递归调用分治逻辑。
代码实现
class Solution {
private:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode dummy(0);
ListNode* curr = &dummy;
while (l1 && l2) {
if (l1->val <= l2->val) {
curr->next = l1;
l1 = l1->next;
} else {
curr->next = l2;
l2 = l2->next;
}
curr = curr->next;
}
curr->next = l1 ? l1 : l2;
return dummy.next;
}
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
if (lists.empty()) return nullptr;
while (lists.size() > 1) {
vector<ListNode*> mergedLists;
for (int i = 0; i < lists.size(); i += 2) {
ListNode* l1 = lists[i];
ListNode* l2 = (i + 1 < lists.size()) ? lists[i + 1] : nullptr;
mergedLists.push_back(mergeTwoLists(l1, l2));
}
lists = mergedLists;
}
return lists[0];
}
};
class Solution:
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
if not lists:
return None
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
curr.next = l1 or l2
return dummy.next
while len(lists) > 1:
merged_lists = []
for i in range(0, len(lists), 2):
l1 = lists[i]
l2 = lists[i + 1] if i + 1 < len(lists) else None
merged_lists.append(mergeTwoLists(l1, l2))
lists = merged_lists
return lists[0]
public class Solution {
private ListNode MergeTwoLists(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
ListNode curr = dummy;
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) {
curr.next = l1;
l1 = l1.next;
} else {
curr.next = l2;
l2 = l2.next;
}
curr = curr.next;
}
curr.next = l1 ?? l2;
return dummy.next;
}
public ListNode MergeKLists(ListNode[] lists) {
if (lists.Length == 0) return null;
List<ListNode> listsList = new List<ListNode>(lists);
while (listsList.Count > 1) {
List<ListNode> mergedLists = new List<ListNode>();
for (int i = 0; i < listsList.Count; i += 2) {
ListNode l1 = listsList[i];
ListNode l2 = (i + 1 < listsList.Count) ? listsList[i + 1] : null;
mergedLists.Add(MergeTwoLists(l1, l2));
}
listsList = mergedLists;
}
return listsList[0];
}
}
var mergeKLists = function(lists) {
if (!lists || lists.length === 0) return null;
while (lists.length > 1) {
let mergedLists = [];
for (let i = 0; i < lists.length; i += 2) {
let l1 = lists[i];
let l2 = (i + 1 < lists.length) ? lists[i + 1] : null;
mergedLists.push(mergeTwoLists(l1, l2));
}
lists = mergedLists;
}
return lists[0];
};
function mergeTwoLists(l1, l2) {
let dummy = new ListNode();
let current = dummy;
while (l1 && l2) {
if (l1.val <= l2.val) {
current.next = l1;
l1 = l1.next;
} else {
current.next = l2;
l2 = l2.next;
}
current = current.next;
}
current.next = l1 || l2;
return dummy.next;
}
复杂度分析
| 复杂度 | 分治法 |
|---|---|
| 时间复杂度 | O(N log k),其中N是所有节点总数,k是链表数量 |
| 空间复杂度 | O(1),只使用常数额外空间(不考虑递归栈空间) |
相关题目
. Merge Two Sorted Lists (Easy)
. Ugly Number II (Medium)