23. 合并K个排序链表
查看题目困难
链表
数组
排序
高频
解法一:分治算法
时间复杂度:O(n*logk) | 空间复杂度:O(logk) | 推荐使用
动画演示
准备就绪 - 输入链表值(用逗号分隔),然后点击开始
代码实现
class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
return merge(lists, 0, lists.length - 1);
}
public ListNode merge(ListNode[] lists, int l, int r) {
if (l == r) {
return lists[l];
}
if (l > r) {
return null;
}
int mid = (l + r) >> 1;
return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
}
public ListNode mergeTwoLists(ListNode a, ListNode b) {
if (a == null || b == null) {
return a != null ? a : b;
}
ListNode head = new ListNode(0);
ListNode tail = head, aPtr = a, bPtr = b;
while (aPtr != null && bPtr != null) {
if (aPtr.val < bPtr.val) {
tail.next = aPtr;
aPtr = aPtr.next;
} else {
tail.next = bPtr;
bPtr = bPtr.next;
}
tail = tail.next;
}
tail.next = (aPtr != null ? aPtr : bPtr);
return head.next;
}
}时间复杂度:O(n*logk)
空间复杂度:O(logk)
分治法:将k个链表分成两组,分别合并,然后再合并结果。时间复杂度为O(n*logk),其中k是链表数量,n是所有链表的节点总数。空间复杂度为O(logk),主要用于递归调用栈。
解法二:迭代法
时间复杂度:O(k*n) | 空间复杂度:O(1)
动画演示
准备就绪 - 输入链表值(用逗号分隔),然后点击开始
代码实现
class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
ListNode ans = null;
for (int i = 0; i < lists.length; ++i) {
ans = mergeTwoLists(ans, lists[i]);
}
return ans;
}
public ListNode mergeTwoLists(ListNode a, ListNode b) {
if (a == null || b == null) {
return a != null ? a : b;
}
ListNode head = new ListNode(0);
ListNode tail = head, aPtr = a, bPtr = b;
while (aPtr != null && bPtr != null) {
if (aPtr.val < bPtr.val) {
tail.next = aPtr;
aPtr = aPtr.next;
} else {
tail.next = bPtr;
bPtr = bPtr.next;
}
tail = tail.next;
}
tail.next = (aPtr != null ? aPtr : bPtr);
return head.next;
}
}时间复杂度:O(k*n)
空间复杂度:O(1)
迭代法:依次合并两个链表,直到所有链表合并完成。时间复杂度为O(k*n),其中k是链表数量,n是所有链表的节点总数。空间复杂度为O(1),只使用了常数级别的额外空间。
解法三:优先队列
时间复杂度:O(n*logk) | 空间复杂度:O(k)
动画演示
准备就绪 - 输入链表值(用逗号分隔),然后点击开始
代码实现
class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
class Solution {
class Status implements Comparable<Status> {
int val;
ListNode ptr;
Status(int val, ListNode ptr) {
this.val = val;
this.ptr = ptr;
}
public int compareTo(Status status2) {
return this.val - status2.val;
}
}
PriorityQueue<Status> queue = new PriorityQueue<Status>();
public ListNode mergeKLists(ListNode[] lists) {
for (ListNode node: lists) {
if (node != null) {
queue.offer(new Status(node.val, node));
}
}
ListNode head = new ListNode(0);
ListNode tail = head;
while (!queue.isEmpty()) {
Status f = queue.poll();
tail.next = f.ptr;
tail = tail.next;
if (f.ptr.next != null) {
queue.offer(new Status(f.ptr.next.val, f.ptr.next));
}
}
return head.next;
}
}时间复杂度:O(n*logk)
空间复杂度:O(k)
优先队列法:使用优先队列维护每个链表的当前头节点。每次取出最小节点,然后将该节点的下一个节点加入队列。时间复杂度为O(n*logk),其中k是链表数量,n是所有链表的节点总数。空间复杂度为O(k),用于存储优先队列中的k个节点。